php 8.2 的 readonly 属性与构造函数属性提升结合,可自动绑定参数为只读属性,无需手动赋值;readonly class 进一步简化语法,所有属性自动只读,但要求构造函数完成全部初始化且继承时子类也须 readonly。

PHP 8.2 的 readonly 属性 + 构造函数属性提升(Constructor Property Promotion)配合使用,能直接省掉手动赋值逻辑,且让不可变性在语法层就锁定——不是靠约定或 getter 模拟,而是语言强制。
构造函数里声明 public readonly 就够了
不用写 $this->name = $name; 这类重复赋值语句,PHP 会自动把参数绑定为只读属性:
readonly class User {
public function __construct(
public readonly string $name,
public readonly int $age
) {}
}
这种写法比 PHP 8.1 的纯 readonly 属性更紧凑,也比手动私有属性 + getter 更安全。关键点:
-
public readonly必须出现在构造函数签名里,不能在类体中单独声明 - 属性初始化仅发生在构造时,之后任何
$user->name = 'xxx'都会抛出Fatal error: Cannot modify readonly property - 不支持
protected readonly或private readonly与属性提升混用(会报语法错误)
只读类(readonly class)让构造函数更“干净”
如果你整个类都该不可变,直接用 readonly class,构造函数里就不用每个属性都写 readonly:
readonly class User {
public function __construct(
public string $name,
public int $age
) {}
}
这时所有属性自动获得只读语义,效果等同于上面显式写 public readonly,但更简洁。注意:
- 类一旦标记为
readonly,就不能再添加非只读属性(比如后期加一个public $cache会直接解析失败) - 构造函数仍必须完成所有属性初始化;漏掉任何一个参数会导致
Uncaught Error: Typed property must not be accessed before initialization - 如果父类是
readonly,子类继承时也必须是readonly,否则编译报错
别在构造函数里做“可变操作”
只读约束只管属性赋值,不管构造函数内部逻辑。但容易踩的坑是:在构造函数里意外修改了本该只读的属性值:
readonly class Config {
public function __construct(public string $host) {
// ❌ 错误:这里已经赋过值,再改会触发只读错误
$this->host = strtolower($this->host);
}
}
正确做法是预处理参数,而不是改已赋值的属性:
- 用参数解构或临时变量处理后再传入:
public function __construct(public string $host) { $this->host = strtolower($host); }不行,$this->host已被自动赋值 - 应改为:
public function __construct(string $host) { $this->host = strtolower($host); }——但这就得放弃属性提升,回到传统写法 - 更推荐:在调用方处理好,保持构造函数纯粹:
new Config(strtolower($rawHost))
真正难处理的其实是嵌套只读对象——比如 readonly class 里含另一个 readonly class 实例,这时候构造顺序和初始化时机稍有不慎就会触发未初始化警告。这类边界情况,光靠语法糖 cover 不住,得靠明确的初始化路径设计。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











