PHP 8.4 的语法变更是面向对象建模的质变:新增属性钩子(强制显式 get/set)、非对称可见性(如 public writeonly)、#[Deprecated] 属性仅限函数/方法/类使用,以及 readonly class 全面禁止运行时修改与克隆。

PHP 8.4 的语法变更不是“加点糖”就能跑通的,不处理属性钩子、不对称可见性、#[Deprecated] 和 readonly 类行为,代码大概率在运行时直接报错或语义错乱。
属性钩子(Property Hooks)必须显式声明 get/set,否则访问会 fatal
PHP 8.4 中,public string $name { get => $this->firstName . ' ' . $this->lastName; } 这类属性钩子一旦定义,就不再允许直接赋值——哪怕属性本身没写 set。尝试 $obj->name = 'xxx' 会触发 Fatal error: Cannot assign to readonly property(即使没加 readonly 修饰符)。
- 只写
get钩子 → 属性变成只读虚拟字段,禁止写入 - 只写
set钩子 → 允许写入但无法读取,读操作抛出Fatal error - 钩子内部不能访问未初始化的依赖属性,否则触发
Notice并中断执行 - IDE 和静态分析工具(如 PHPStan)会据此推导类型流,但旧版工具可能报“unknown property”误报
不对称可见性让 public/protected/private 失效,必须用新语法
以前靠 getter/setter 模拟的“只读属性”,现在要改用 public readonly 或 public writeonly。但注意:writeonly 是 PHP 8.4 新增关键字,不是用户自定义标识符,且仅支持属性级,不支持方法。
-
public readonly string $id;→ 构造函数中赋值后不可再改,且外部不可写 -
public writeonly string $token;→ 可写不可读,读取时直接Fatal error - 旧代码里用
private $x;+public function getX()的模式,必须整体重构为钩子或新可见性声明 - 继承链中若父类用
public readonly,子类不能覆盖为可写,否则解析失败
#[Deprecated] 属性不能套在变量或普通表达式上,仅限函数/方法/常量
这个属性是 PHP 8.4 新增的废弃标注机制,但它有严格作用域限制:只能用于 function、method、const、class,不能用于 property、parameter 或 return 类型声明。
- ✅ 正确:
#[Deprecated('Use newHandler() instead')] public function oldHandler(): void { ... } - ❌ 错误:
public #[Deprecated] string $legacyField;→ 解析失败 - 错误信息是
Attribute #[Deprecated] is not allowed on this type of declaration - 它不会自动触发
E_USER_DEPRECATED,需配合运行时检查逻辑(比如在方法体开头手动trigger_error(..., E_USER_DEPRECATED))
readonly 类和构造器参数绑定更紧,继承和 clone 行为已变更
PHP 8.4 中 readonly class 不再允许任何属性被修改,包括通过反射或 __set()。更重要的是,构造器参数如果带 readonly,其初始化必须在构造函数签名中完成,不能延迟到函数体内。
-
readonly class User { public function __construct(public readonly string $id) {} }✅ -
readonly class User { public readonly string $id; public function __construct(string $id) { $this->id = $id; } }❌ 报错:Cannot initialize readonly property in constructor body -
clone一个readonly对象会失败,PHP 直接拒绝克隆,而非复制后冻结 - 第三方库(如 Doctrine、Laravel 的 DTO 工具)若未适配,调用
new static(...)或反射填充时可能崩溃
最易被忽略的点是:属性钩子和不对称可见性不是“可选增强”,而是语言层面对访问控制模型的重定义。你无法通过 polyfill 或运行时判断绕过,必须在 AST 层面识别并重写。Rector 的 php84 规则集能处理大部分 #[Override] 和数组类型细化,但对钩子和 writeonly 尚无全自动迁移路径——得人工逐个确认语义是否等价。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











