PHP 8.4 升级笔记:property hooks 和 readonly 不能共存,E_STRICT 移除会改 CI 行为
PHP 8.4 于 2024-11-21 发布,活跃支持到 2026-12-31,安全修复到 2028-12-31。下面是迁移时真正会踩到的不兼容点。
新特性,以及它们自带的坑
Property hooks 是 8.4 的头号特性:属性可以挂 get/set 逻辑,没有 backing store 时就是虚拟属性。几个坑:
- 传给构造函数的值必须匹配声明类型,不管 hook 接受什么类型。
- property hooks 与
readonly属性不兼容,手册里明确写了这一点。 - 获取引用或间接修改可能绕过 set hook。如果调用者经常修改数组元素,避免在这个属性上用 hook,尽量「替换整个数组」。
不对称可见性:可以设成 public 读、private(set) 写。可见性是 get-visibility,get visibility 不能比 set visibility 更严格。
新增数组函数:array_find、array_find_key、array_any、array_all。
#[Deprecated] attribute:用户态弃用标记,触发 E_USER_DEPRECATED,注意不是 E_DEPRECATED。
新 DOM API:Dom 命名空间,HTML5 标准兼容解析,Dom\HTMLDocument / Dom\XMLDocument;旧 DOM 类仍然保留。
PDO 驱动特定子类:Pdo\MySql、Pdo\Pgsql、Pdo\Sqlite 等。
Lazy objects:主要用于框架和基础设施层。
会表现为随机测试失败的变更
E_STRICT被移除,E_STRICT常量已弃用。遗留代码或配置里引用它,CI 行为就会跟着变。- JIT 配置默认值变了(OPcache 侧),从 tracing 改了默认值。
- 扩展更严格:Date、Intl、PDO、Reflection、SPL、SQLite、XMLReader 的多个扩展类常量现在有类型。
- 一些函数改为抛
ValueError,不再静默接受无效输入:round()的无效 mode、str_getcsv()分隔符长度不为 1 字节。round()传无效 mode 现在抛ValueError,之前会当成PHP_ROUND_HALF_UP。 - SimpleXML 迭代行为变化,避免意外 rewind,此前可能导致无限循环。
- 部分 PDO 属性按驱动表现为布尔而非整数。
这些属于「不早点在 8.4 下跑测试套件,就会表现为随机测试失败」的变更。
迁移顺序
- 先把 8.4 加到 CI 里跑测试套件,把警告和弃用当信号。
- 只在新代码里用
array_find/array_any/array_all。 - 新 DTO 用不对称可见性。
- 明显能替代样板代码的地方加 property hooks。
- 用
#[Deprecated]做内部 API 清理。 - 新 DOM API 先在脚本或隔离模块里用。
- lazy objects 留给框架层。