php 8.0+ 的交叉类型写作 a&b,仅支持用于参数、返回值和属性声明,不支持局部变量;必须至少两个接口或类(至多一个类),且需实际同时满足所有类型契约。

PHP 8.0+ 的交叉类型(Intersection Types)怎么写
PHP 不支持传统意义上的“交叉类型变量定义”,但自 8.0 起引入了真正的交叉类型语法,仅用于函数参数、返回值和属性声明,不能用于 $var 这种局部变量的类型标注。
你没法写 $x: A&B; 或 var $x: A&B; —— PHP 解析器直接报错 Parse error: syntax error, unexpected token "&"。
- 交叉类型只允许出现在类型声明位置:参数类型、返回类型、类属性(
public A&B $prop;)、类常量(PHP 8.2+) - 必须至少两个接口或类,且不能含
mixed、void、null等无效组合 - 类名参与交叉时,最多一个具体类,其余必须是接口(否则运行时报
Fatal error: Intersection types may only contain at most one class)
为什么不能给普通变量加交叉类型
PHP 的类型系统是“声明式”而非“推导式”:类型信息只在编译/运行时做契约检查,不用于变量存储结构的重构。局部变量没有类型声明语法位,所以 & 在赋值语句中不是类型操作符,而是按位与运算符。
常见误写:$x = $a & $b; —— 这里 & 是整数位运算,跟类型完全无关;想表达“这个变量同时满足 A 和 B”,PHP 没提供运行时类型绑定机制。
立即学习“PHP免费学习笔记(深入)”;
Avactis是一个强大的PHP在线购物系统拥有多个版本包括开源版本。它具备一个在线购物系统所需要的所有功能从产品到会员管理,订单和营销。可以无限分类和为产品指定任务数量的图片(支持自动生成缩略图)。使用自定义字段功能,让你可以更好地定义一个产品。该系统提供以非常灵活的方式来创建任意类型的促销活动如设置折扣代码,基于价格的折扣或基于数量的折扣等。
- 试图用
/** @var A&B */ $x = ...;—— PHPStan/PHPStorm 可能识别,但 PHP 解释器忽略,无运行时效果 - 用
gettype()或instanceof手动校验?可以,但那是逻辑判断,不是类型定义 - IDE 提示“expected A&B”只是静态分析建议,不代表语言支持该语法
实际能用交叉类型的三个地方
只有这三处写法是合法且生效的(PHP 8.0+):
- 参数:
function foo(Iterator&Countable $it): void { ... } - 返回值:
function bar(): DateTimeImmutable&Stringable { return new DateTimeImmutable(); } - 属性:
public LoggerInterface&Psr\Log\LoggerAwareInterface $logger;
注意:返回值必须确保实际返回的对象**同时实现所有类型**,否则运行时报 TypeError。例如上面 bar() 若返回纯 DateTimeImmutable(未实现 Stringable),就会失败 —— 即使它继承自实现了该接口的父类也不行,必须显式实现或使用 implements 声明。
交叉类型和联合类型别搞混
A|B 是联合类型(“是 A 或 B”),A&B 是交叉类型(“既是 A 又是 B”),语义相反,错误混用会导致行为不符合预期。
- 写成
array|string是对的,表示接受数组或字符串 - 写成
ArrayAccess&Traversable表示必须同时支持下标访问和迭代,比如ArrayObject符合,但普通array不符合(它不是对象,不实现接口) - IDE 或静态分析工具可能把
A&B当作A|B提示,这是工具 bug,以 PHP 运行时行为为准
交叉类型真正起作用的地方,是当你需要一个对象“必须具备多个契约能力”时——比如既要可迭代又要可计数,或者既要记录日志又要能被序列化。这时候硬编码检查一堆 instanceof 很啰嗦,而交叉类型让契约更紧凑、更易读。但它不会帮你自动组合对象,也不会改变变量本身的动态性。










