PHP 8.2 正式引入析取范式(DNF)类型语法,即 (A & B) | C,用于精准表达「既是 A 又是 B,或者属于 C」的类型契约;该语法支持参数、返回值和属性声明,但交集部分必须用括号显式包裹,且运行时传入值须实际满足任一分支,否则触发 Fatal error。

PHP 8.2 正式引入了析取范式(Disjunctive Normal Form, DNF)类型语法,它不是新函数或扩展,而是类型系统的一次关键升级——允许你用 (A & B) | C 这样的结构精准表达「既是 A 又是 B,或者属于 C」的契约。它解决的是过去只能靠运行时 if 判断、注释说明或手动 instanceof 检查的类型模糊问题。
DNF 类型怎么写才合法
语法必须严格遵循括号分组规则:
- 交集部分 A & B 必须用圆括号包裹,例如
(JsonSerializable & Throwable) - 再与联合类型用
|连接,例如(JsonSerializable & Throwable) | array - 错误写法:
JsonSerializable & Throwable | array→ 解析失败,PHP 不接受无括号的混合优先级 - 支持位置:函数参数、返回值、类属性声明,全部可用
哪些类型可以参与 DNF 组合
不是所有类型都能自由组合,需注意兼容性边界:
- 接口与类可交集,如
(RequestInterface & HTMLRequest),前提是该实例同时实现/继承两者 - 类与 final 类可交集,但不能与不兼容的父类冲突(如
(Exception & JsonSerializable)合法,但运行时若传入未实现jsonSerialize()的 Exception 实例,仍会报 Fatal error) -
null、true、false 现在是独立类型,可直接参与 DNF,例如
(string & Trimmed) | null或bool | true - 不能交集内置标量类型(如
string & int),PHP 会报语法错误
如何验证 DNF 是否生效
别只看代码是否通过解析,要确认运行时行为和环境支持:
立即学习“PHP免费学习笔记(深入)”;
- 调用
phpinfo(),搜索 DNF type parsing 字段,值为 enabled 才表示引擎已启用该语法 - 同时检查 Standalone type support 是否为 true,确保
null、true、false可单独使用 - 写个最小测试函数,传入不满足任一分支的值,应触发
TypeError而非静默通过 - 若用 PHPStan / Psalm 做静态分析,需升级到支持 PHP 8.2 DNF 的版本(如 PHPStan 1.10+),否则会误报类型错误
常见踩坑点与修复建议
DNF 很强大,但容易因理解偏差导致运行时报错:
-
类型声明 ≠ 行为保证:写
(Throwable & JsonSerializable)只校验类型兼容性,不自动给 Exception 加上jsonSerialize()方法;修复方式是让自定义异常类真正实现该接口 -
数组键名不参与类型推导:不能写
(array{status: string} & Countable) | null,PHP 8.2 不支持带形状的数组参与交集,仅支持完整类型名 -
框架 DTO 类易被误用:如 Laravel 的 Request 类常被当作
Request使用,但若实际传入的是普通stdClass,即使声明(Request & Validatable) | null也会失败;应确保运行时对象真实满足全部接口



















