php 8.3 只读类声明为 readonly class,所有 public 属性自动只读且必须在构造函数中初始化;禁止 static 成员;reflectionclass::isreadonly() 返回 true,属性 isreadonly() 全为 true;支持 serialize(),但 unserialize() 需自定义 __unserialize(),否则报错;json_encode() 正常工作。

你需要为 PHP 8.3 的只读类(readonly class)整理一份实操笔记,重点覆盖声明语法、初始化约束、继承限制、反射检测和序列化行为,确保每条记录都对应真实可验证的运行时表现。
声明只读类并验证基础行为
在 PHP 8.3 中,使用 readonly class 关键字声明整个类为只读,该类所有属性自动成为只读属性,无需逐个加 readonly 修饰符。
创建一个文件 User.php,写入以下内容:
readonly class User { public string $name; public int $id; public function __construct(string $name, int $id) { $this->name = $name; $this->id = $id; } }
保存后执行 php User.php 不会报错;但若新增一行 $u = new User("A", 1); $u->name = "B";,运行时将抛出 Fatal error: Cannot modify readonly property User::$name。
注意:只读类不能包含 static 属性或方法,否则解析阶段直接报错 —— 这是语法硬性限制,不是运行时检查。
只读类的构造函数与初始化规则
只读类的实例必须在构造函数中完成全部属性赋值,且不允许延迟初始化。
第一步:定义类时省略构造函数参数类型提示,仅保留属性声明:
readonly class Config { public string $env; public array $features; }
第二步:在构造函数中显式赋值所有 public 属性:
public function __construct() { $this->env = 'prod'; $this->features = ['cache' => true]; }
第三步:尝试在构造函数外赋值(如在另一个方法里)会触发致命错误;若某个属性漏赋值,实例化时立即报 Uninitialized readonly property —— 这比普通只读属性更严格,因为它是类级强制校验。
反射检测只读类及其属性
方法一:用 ReflectionClass 判断类是否为只读类
$ref = new ReflectionClass(User::class); var_dump($ref->isReadOnly()); // bool(true)
方法二:遍历属性并确认其只读状态
$props = $ref->getProperties(); foreach ($props as $prop) { echo $prop->getName() . ': ' . ($prop->isReadOnly() ? '✅' : '❌') . "\n"; }
这一步输出结果全是 ✅,因为只读类内所有属性自动获得只读标记,无需额外声明。如果某属性被声明为 static,则 ReflectionClass 构造会失败,根本走不到这一步。
只读类的序列化与反序列化处理
只读类支持 serialize(),但 unserialize() 必须配合自定义 __unserialize() 方法,否则会因无法写入只读属性而失败。
在类中添加:
public function __unserialize(array $data): void { $this->name = $data['name'] ?? 'unknown'; $this->id = $data['id'] ?? 0; }
然后执行:
$u = new User('Test', 99); $s = serialize($u); $restored = unserialize($s);
若未实现 __unserialize(),unserialize() 调用将抛出 Cannot initialize readonly property 错误。JSON 序列化不受影响:json_encode($u) 可正常输出所有 public 属性值。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











