### [PHP 8.2 readonly class 让不可变对象真正可用](https://www.huociguo.com/article/237) **Published:** 2026-07-27T17:25:16 **Author:** 米了 **Excerpt:** 在 PHP 8.1 引入 readonly 属性修饰符之后,不可变对象(Immutable Object) 的构建仍然面临诸多限制。开发者需要为每个属性逐个标注 readonly,构造函数参数与属性声明之间存在重复代码,且继承场景下的可变性 在 PHP 8.1 引入 `readonly` 属性修饰符之后,**不可变对象(Immutable Object)** 的构建仍然面临诸多限制。开发者需要为每个属性逐个标注 `readonly`,构造函数参数与属性声明之间存在重复代码,且继承场景下的可变性控制并不彻底。PHP 8.2 推出的 `readonly class` 语法从根本上解决了这些问题,使得**值对象(Value Object)** 和**数据传输对象(DTO)** 的不可变性声明变得简洁、可靠且具备编译期保障。 ![](https://api.huociguo.com/wp-content/uploads/2026/07/PHP-8.2-readonly-class-%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%AF%B9%E8%B1%A1%E5%9B%BE%E7%89%87%E7%94%9F%E6%88%90%E9%9C%80%E6%B1%82-27176349f6-1.png "PHP-8.2-readonly-class-不可变对象图片生成需求-27176349f6-1") ## **readonly class 的核心语法** PHP 8.2 允许在类声明级别使用 `readonly` 关键字: ```php currency !== $other->currency) { throw new InvalidArgumentException('Currency mismatch'); } return new Money($this->amount + $other->amount, $this->currency); } } ``` `Money` 实例一旦创建,`$amount` **与** `$currency` **永不可变**。运算操作不修改当前对象,而是返回全新实例。这种设计**消除了共享引用导致的副作用**,在多线程协程环境(如 Swoole、FrankenPHP)中尤其重要——**无锁读取无需担心竞态条件**。 ## **运行时性能与内存收益** `readonly class` 在 Zend Engine 层面享有优化空间。由于属性写入被永久禁止,**Zend VM 可以跳过写时复制(Copy-On-Write)检查**,直接对属性值进行引用共享而非深拷贝。对于嵌套大量值对象的业务模型(如订单聚合根包含多个 Money、Address 值对象),**内存占用在高并发场景下可降低 15%–30%**。 此外,OPcache 对 readonly 类的属性布局进行静态分析时,**无需预留动态属性哈希表空间**,进一步压缩对象头开销。 ## **使用边界与注意事项** `readonly class` 并非适用于所有场景,以下约束需要明确: **动态属性被彻底禁止。** `readonly class` 隐式启用 `#[AllowDynamicProperties]` 的反面效果,任何未声明的属性赋值都会触发致命错误。 **延迟初始化(Lazy Initialization)受限。** 所有属性必须在构造函数执行完毕前完成赋值,**依赖外部注入后二次填充的模式无法直接使用**。 **序列化兼容性。** `unserialize()` 恢复对象时,若序列化数据中包含与当前类定义不匹配的属性,反序列化过程会失败。建议对 readonly 类实现自定义的 `__serialize()` / `__unserialize()` 逻辑。 ## **总结** PHP 8.2 的 `readonly class` 将不可变性从**属性级别的语法糖**提升为**类级别的类型契约**。对于追求**防御式编程**和**函数式代码风格**的 PHP 项目而言,这是自 PHP 7.4 类型属性以来最具工程价值的新特性。在构建支付系统、配置中心、领域模型等需要**严格状态一致性**的模块时,优先采用 `readonly class` 能够显著降低因意外 mutation 引发的线上故障概率。 **Categories:** PHP教程 ---