php 8.4 的契约编程以接口和类型系统强化为核心,支持接口中声明带 get/set 访问器的属性、只读接口约束输入、property hook 实现赋值时自动校验,并可通过 rector 自动化落地契约。

PHP 8.4 的契约编程能力,核心落在 接口(Interface) 和 类型系统强化 两个支点上。它不再只是“声明方法签名”,而是让接口能真正参与运行时约束、静态分析校验和 IDE 智能提示,从而在工程层面提前拦截非法入参,降低运行时错误风险。
接口支持属性契约:让字段级约束可声明、可继承
PHP 8.4 允许在接口中直接声明带 get/set 访问器的属性,形成字段级行为契约:
- 接口定义明确要求实现类必须提供对某个属性的受控读写逻辑,而不仅是方法
- 例如:
interface HasId { public string $id { get; set; } }—— 强制所有实现类的$id不仅存在,还必须支持自定义获取与赋值规则 - 子类若仅声明
public string $id(无访问器),仍满足该接口;但若需扩展校验逻辑(如非空、格式、范围),就必须显式实现访问器,契约即落地
只读属性 + 接口组合:构建不可变输入契约
对函数或构造器入参,可结合 readonly 与接口类型提示,确保传入对象状态稳定:
- 定义只读 DTO 接口:
interface UserInput { public readonly string $email; public readonly int $age; } - 函数签名使用该接口:
function processUser(UserInput $input): void - 调用方必须传入满足只读约束的对象(如通过只读类实例化),避免函数内部意外修改输入源
- 配合静态分析工具(如 PHPStan),可在编码阶段报出“尝试写入只读属性”的错误
Property Hook 配合类型断言:在赋值入口做精准校验
利用 Property Hook 的 set 逻辑,在属性被赋值的第一时间执行参数验证:
- 不依赖外部校验函数,校验逻辑随属性绑定,无法绕过
- 示例:
public string $email { set => filter_var($value, FILTER_VALIDATE_EMAIL) !== false ?: throw new InvalidArgumentException('Invalid email'); } - 当其他代码执行
$obj->email = 'test'时,校验自动触发;IDE 和 LSP 能识别该 setter,提供准确的类型提示 - 相比传统 setter 方法,语法透明,调用方无需感知,但安全边界已内建
配合 Rector 实现契约落地自动化
大型项目升级过程中,手动补全契约易遗漏。Rector 可批量注入类型与约束:
- 启用
php84: true规则集,自动为已有 getter/setter 方法生成 Property Hook 语法,将校验逻辑前移到属性层 - 用
TypedPropertyRector为未声明类型的公共属性补全类型,再结合接口约束,形成完整入参契约链 - 通过
--dry-run预览变更,确认所有新增的set逻辑符合业务校验预期,再提交落地
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











