php 8.2 引入 disjoint normal form(dnf)类型,支持联合类型(php 8.0)与交集类型(php 8.1)的组合声明,实现更精确的参数、返回和属性类型约束。

什么是 Disjoint Normal Form 类型
PHP 8.1 没有引入 Disjoint Normal Form(DNF)类型——这个术语在 PHP 官方文档、RFC 或任何已发布特性中均未出现。你实际遇到的,很可能是对「纯交集类型(pure intersection types)」或「联合类型(union types)」的误称,或是混淆了其他语言(如 TypeScript、Rust)中的逻辑术语。
PHP 8.1 真正支持的组合类型只有 union 和 intersection
PHP 8.1 正式支持两种组合类型语法,它们语义明确、无歧义:
-
|表示联合类型(union):值可以是其中任一类型,例如string|int -
&表示交集类型(intersection):值必须同时满足所有类型约束,例如Traversable&Countable
注意:& 类型仅适用于对象类型(class/interface),不能用于标量或 mixed;而 | 不允许 null 出现在非 nullable 上下文中(除非显式写成 ?string 或 string|null)。
常见错误:把 intersection 当作逻辑“且”来滥用
开发者常误以为 DateTimeInterface&JsonSerializable 能表达“既是日期又能 JSON 序列化”,但实际它只校验类型兼容性,不保证行为完备性。比如:
// 这段代码能通过类型检查,但运行时可能失败
function serializeDate(JsonSerializable&DateTimeInterface $obj): string {
return json_encode($obj->jsonSerialize()); // DateTimeInterface 没有 jsonSerialize() 方法!
}
原因在于:PHP 的 intersection 类型不进行方法签名合并推导,它只确认变量是否同时被声明为这两个接口的实例——而 DateTime 类本身并未实现 JsonSerializable,所以传入 new DateTime() 会直接报 TypeError。
- intersection 类型适合用于已有类/接口已明确实现多个契约的场景(如自定义 DTO 实现了
ArrayAccess & JsonSerializable) - 不要指望它自动“补全方法”或做运行时行为推断
- 若需动态能力组合,应使用 traits 或显式适配器,而非依赖类型系统
为什么没有 DNF?PHP 的类型系统不建模逻辑公式
DNF(如 (A & B) | (C & D))属于命题逻辑表达式,在 PHP 中无法直接书写。虽然你可以嵌套写成 (A&B)|(C&D),但 PHP 8.1 不支持这种语法——它会解析失败或报错 ParseError: syntax error, unexpected '|'。
目前唯一合法的写法是平铺联合,例如:
// ✅ 合法:两个独立的 intersection 类型用 | 连接
function handleInput(Iterator&Countable|ArrayAccess&Traversable $input): void { ... }
// ❌ 非法:括号 + & + | 混合不被解析器接受
function badExample((A&B)|(C&D) $x): void { ... }
换句话说:PHP 类型系统是“扁平联合 + 单层交集”的组合,不是逻辑代数引擎。需要复杂契约时,应拆解为多个函数重载、参数对象封装,或用 docblock + 静态分析工具(如 PHPStan)补充校验。
最易忽略的一点:intersection 类型在函数返回值中几乎无实用价值,因为 PHP 无法在返回处“构造”一个同时满足多个接口的匿名对象;它只在参数和属性声明中有意义,且前提是传入值真实实现了全部接口。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











