PHP 8.4 是面向对象建模的质变:新增属性钩子(支持内联 get/set)、readonly class(整类不可变)、非对称可见性(如 private(set)),使 DTO 等场景实现编译期+运行期双重强制。
PHP 8.4 和 PHP 8.3 的核心区别不是“小幅升级”,而是面向对象建模能力的一次质变:8.3 是稳中求进的工程优化,8.4 则引入了真正改变类设计范式的语言原语——尤其是属性钩子、只读类、非对称可见性这三项,让 DTO、值对象、配置类等场景从“靠约定和文档约束”走向“编译期+运行期双重强制”。
PHP 8.4 允许在属性声明时直接内联 get 和 set 逻辑,IDE 和静态分析工具能原生识别,不再依赖 @property 注释。
class User {
public string $name {
get => $this->firstName . ' ' . $this->lastName;
set => [$this->firstName, $this->lastName] = explode(' ', $value, 2);
}
private string $firstName = '';
private string $lastName = '';
}get 中抛异常不会被 isset() 或 empty() 捕获,仍会返回 false,需改用 property_exists() + 显式访问判断$this->__get() 或 $this->__set(),会无限递归PHP 8.3 修复了 8.1 引入的 readonly 属性在继承和构造函数中的一些边界问题;而 PHP 8.4 新增 readonly class,整类实例化后所有属性(包括动态添加的)一律冻结。
readonly class 适合纯数据载体:配置类、API 响应 DTO、领域事件对象public readonly string $host; 只锁该属性;8.4 的 readonly class Config { public string $host; } 锁整个对象状态__set() 尝试修改,也会抛出 Error(不是 Exception),无法被 try/catch 捕获readonly class 不允许定义普通构造函数,必须用构造函数属性提升(public function __construct(public string $host) {})它让一个属性对外只读、对内可写,彻底替代过去“public $id; private $_id;”这类冗余模式。
class Post {
public private(set) int $version = 0;
public string $slug { get => $this->generateSlug(); }
private function generateSlug(): string { /* ... */ }}
$htmlCache,外部只读,内部生成后赋值)
注意:
private(set) 属性仍可通过反射绕过(但这是所有 PHP 访问控制的共性限制)readonly 同时使用(语法冲突)这些不是语法革命,但显著改善维护性和表达力:
#[Deprecated] 可标注方法/函数/常量,并支持 message 和 since 参数:#[Deprecated(message: 'Use newPaymentProcessor() instead', since: '8.4.0')]function legacyPay() {} —— 比注释更可靠,php -l 和 IDE 都能识别BcMathNumber 把 BC 数学变成面向对象:use BcMathNumber;$a = new BcMathNumber('0.1');$b = new BcMathNumber('0.2');echo $a + $b; // "0.3" —— 运算符重载 + 自动精度管理,告别 bcadd() 字符串地狱DomHTMLDocument::createFromString() 正确解析 HTML5 语义(如自闭合标签、void 元素),不再需要先 hack 成 XHTML 再加载真正的分水岭在于:PHP 8.3 让你写得更快,PHP 8.4 让你想得更清楚——一旦开始用 readonly class 和属性钩子,你就很难再回到靠文档和测试来保证不变性的老路了。