PHP 8.3 中只读属性的空数组必须声明类型并初始化为常量表达式,如 public readonly array $items = [];,不可延迟赋值或省略类型。

PHP 8.3 中定义空数组配合只读属性,核心不是“怎么写 []”,而是“在哪初始化、带什么类型、是否可变”。空数组本身仍是 [],但作为 readonly 属性时,必须在声明时就明确其类型与默认值,且不能留空或延迟赋值。
只读属性中声明空数组的合法写法
PHP 8.3 允许为 readonly 属性直接赋默认值,空数组属于支持的数组字面量,但必须满足两个前提:类型声明明确 + 默认值为常量表达式。
-
✅ 合法示例:
public readonly array $items = [];private readonly array<string> $tags = [];</string>(需 PHPStan/IDE 支持泛型注解)protected readonly array $config = ['debug' => false]; -
❌ 非法示例:
public readonly array $data = $this->loadDefaults();(函数调用不被允许)public readonly array $cache = [];但未声明类型(如private array $cache = [];缺少readonly关键字则不构成只读)
为什么不能只写 public readonly $list = [];?
缺少类型声明会触发 PHP 8.3 的严格模式警告,且静态分析工具(如 PHPStan)无法推断该数组元素类型,导致后续 foreach 或方法返回值校验失效。
- 必须显式写出
array类型:public readonly array $list = []; - 若需语义更精确,推荐配合 PHPDoc 注解:
/** @var array
*/ public readonly array $nodes = []; - 构造函数中不可再重复赋值——只读属性一旦在声明时设了默认值,构造函数里就不能再写
$this->list = [...],否则报错
空数组只读属性的典型使用场景
适用于配置类、DTO、节点容器等强调不可变性的结构,避免运行时意外清空或覆盖。
立即学习“PHP免费学习笔记(深入)”;
-
配置对象:
class ApiConfig { public readonly array $headers = ['Content-Type' => 'application/json']; } -
DOM 节点暂存(适配未来 NodeList):
class NodeCollector { public readonly array $collected = []; }后续通过外部逻辑填充(如遍历后array_push($collector->collected, $node)),但数组容器本身不可替换 -
错误收集器:
class Validator { public readonly array<string> $errors = []; }</string>错误条目可追加,但整个错误列表引用不可重置
常见陷阱与规避方式
看似简单,但几个细节容易引发运行时错误或类型失察。
-
不要在构造函数中覆盖已声明默认值的只读数组:
声明了
public readonly array $data = [];,就不要再在__construct()里写$this->data = $input; -
空数组默认值 ≠ 可动态扩展的“活列表”:
$obj->data[] = 'new'是允许的(修改内容),但$obj->data = ['a', 'b']是禁止的(替换整个数组) -
泛型提示依赖 IDE 或静态分析,非运行时强制:
/** @var array<int> */ public readonly array $ids = [];</int>不影响执行,但能帮你在foreach ($obj->ids as $id)时获知$id是 int 类型



















