PHP 8.2 的 readonly 属性仅允许在构造函数中赋值一次,运行时强制不可变;必须全部初始化,支持属性提升和传统赋值两种写法,实例化后任何修改均报错。

PHP 8.2 的 readonly 属性配合构造函数使用,核心在于“只允许在构造函数中赋值一次”,之后任何写操作都会触发运行时错误。这种机制不是靠类型系统静态检查,而是由引擎在运行时强制保障不可变性。
构造函数是唯一合法赋值入口
所有 readonly 属性(无论是否显式声明为 readonly)都必须在构造函数中完成初始化。不能延迟赋值、不能在其他方法里赋值、也不能留空不赋值。
- 支持属性提升写法:直接在构造参数中声明并自动绑定属性,最简洁
- 也支持传统写法:在构造函数体内用
$this->prop = $value赋值 - 不允许在构造函数外(包括
__construct之后的任何时刻)修改
两种主流写法对比
推荐写法(属性提升):代码更紧凑,语义更清晰
readonly class User {
public function __construct(
public string $name,
public int $age,
private string $email
) {}
}
此时 $name、$age、$email 全部自动成为只读属性,且已在构造时完成初始化。
立即学习“PHP免费学习笔记(深入)”;
传统写法(显式赋值):适合需要额外逻辑或兼容旧风格的场景
readonly class Config {
public string $host;
public int $port;
public function __construct(string $host, int $port) {
$this->host = $host;
$this->port = $port;
// 可在此处做校验、转换等操作
if ($port < 1 || $port > 65535) {
throw new InvalidArgumentException('Invalid port');
}
}
}
常见错误与注意事项
以下操作在实例化后都会报错:“Cannot modify readonly property”
-
$user->name = 'Tom';—— 即使属性是public也不行 -
$config->host .= ':8080';—— 追加操作也属于修改 - 在非构造函数中尝试重新赋值,哪怕值相同
- 子类继承只读类时,若未声明
readonly,会直接编译失败(不是运行时错误)
只读类中构造函数的特殊要求
因为所有属性必须一次性初始化,构造函数承担了全部状态设定责任:
- 不能省略构造函数(除非类无属性,但这种情况极少)
- 父类是只读类时,子类构造函数必须调用
parent::__construct() - 子类若扩展新属性,也必须在自己的构造函数中初始化,并保持只读性
- 不支持在构造函数中跳过某个属性的赋值(否则会报错:property must be initialized)



















