dnf类型必须用括号显式分组交集:php 8.2要求所有含|的&操作数必须加括号,如(string|int)&traversable,否则报parseerror;它仅用于静态分析,不改变运行时行为。

DNF类型必须用括号显式分组交集
PHP 8.2 的 DNF(析取范式)类型不是简单拼接 union 和 &,而是要求:所有交集(&)必须被括号包裹,否则会报 ParseError: syntax error。这是硬性语法规则,不是风格建议。
常见错误写法:string|int&Traversable —— 这会直接解析失败,因为 & 优先级未被明确界定。
正确写法必须是:string|int&(Traversable&Countable) 或更清晰的 (string|int)&Traversable&Countable(注意最外层括号可选,但每个 & 左右操作数若含 | 就必须括起来)。
- 只含并集:
string|int|float→ 无需括号 - 只含交集:
Traversable&Countable&Iterator→ 无需括号 - 混合时,交集部分必须括起:
string|(Traversable&Countable)✅,string|Traversable&Countable❌
别把DNF当“万能胶”去套运行时值
DNF 类型是编译期静态检查工具,它不改变运行时行为,也不做类型转换或过滤。写 function foo((string|int)&JsonSerializable $x): void 并不会让传入的 int 自动变成 JSON 可序列化对象 —— 它只是告诉 PHP:这个参数必须**同时是 string 或 int,并且实现了 JsonSerializable 接口**。
所以这类类型实际适用场景很窄:
- 你有一个类既继承自
BaseModel又实现了ArrayAccess,想精准约束:BaseModel&(ArrayAccess&Countable) - 第三方库返回泛型对象,你想表达“要么是
stdClass,要么是实现了__toString()和JsonSerializable的类”:stdClass|(Stringable&JsonSerializable) - 避免误用:不要用
array|string&Countable试图覆盖“数组或字符串”,因为string永远不实现Countable,这个类型永远无法满足
与 PHPStan / Psalm 的兼容性差异要手动对齐
PHP 8.2 原生解析器接受的 DNF 语法,和 PHPStan/ Psalm 的类型推断引擎不一定完全同步。比如:
(A&B)|C 在 PHP 解析器里合法,但旧版 PHPStan(≤1.10)可能报 Unknown type;而 A&(B|C) 在 Psalm 中某些版本会警告“intersection with union not supported”。
实操建议:
- 升级到 PHPStan ≥1.11 和 Psalm ≥5.27(2026 年主流版本已支持)
- 在
phpstan.neon中显式启用实验性特性:features: { dnf_types: true } - CI 中加一行验证:
phpstan analyse --level max --no-progress src/ | grep -q "Unknown type",防止本地 OK 但 CI 报错
readonly 类 + DNF 类型组合时注意属性初始化限制
当你在一个 readonly class 里声明 DNF 类型属性,比如:public (string|int)&JsonSerializable $data;,那它的赋值必须在构造函数中完成,且右侧值必须**静态可判定满足该类型**。
这意味着不能写:$this->data = json_decode($json, false); —— 因为 json_decode 返回 mixed,PHP 无法在编译期确认它同时满足 string|int 和 JsonSerializable。
可行做法只有两种:
- 用字面量或已知类型实例赋值:
$this->data = new MyDataObject(); // MyDataObject implements JsonSerializable & is string|int-castable - 用断言 + 类型注解辅助静态分析:
assert($value instanceof JsonSerializable && is_string($value) || is_int($value)); $this->data = $value;(需配合 PHPStan 的assert插件)
DNF 类型本身不提供运行时守卫,它的价值全在 IDE 提示和静态分析阶段 —— 写错括号、配错交集、或指望它自动 cast,都会在开发早期就卡住。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











