PHP 8.1 的交集类型(T1&T2)表示值必须同时满足多个类型约束,仅适用于类、接口、trait,要求共存且非互斥,用于强化多行为契约,如Loggable&Cacheable。

PHP 8.1 引入的交集类型(Intersection Types)不是用来求数组元素重合的,而是用于类型声明——它表示一个值**必须同时满足多个类型约束**。这点常被初学者误解,误以为是 array_intersect() 那类数据操作函数。
交集类型的本质:多类型“与”关系
语法为 T1&T2&T3,意思是该变量或返回值必须既是 T1,又是 T2,又是 T3。它不适用于标量(如 int、string),只对**类、接口、trait**有效,且要求这些类型之间能共存(不能互斥,比如不能同时是两个 final 类)。
典型适用场景:
- 一个对象既要实现
JsonSerializable接口,又要实现Stringable接口 - 一个服务类既要继承基类
Service,又要使用 traitRetryable,还要实现Loggable接口 - 依赖注入时,明确要求传入的对象具备多种行为能力
真实可用的实战写法
以下代码在 PHP 8.1+ 可直接运行:
立即学习“PHP免费学习笔记(深入)”;
interface Loggable { public function log(string $msg): void; }
interface Cacheable { public function cache(string $key, $value): void; }
<p>class UserService implements Loggable, Cacheable
{
public function log(string $msg): void { /<em> ... </em>/ }
public function cache(string $key, $value): void { /<em> ... </em>/ }
}</p><p>function processService(Loggable&Cacheable $service): void
{
$service->log('Starting...');
$service->cache('user_count', 100);
}调用时,只有同时实现两个接口的对象才被接受;传入仅实现其一的实例,PHP 会报 Fatal error: Uncaught TypeError。
和联合类型、泛型的关键区别
别混淆这三者:
-
联合类型(
int|string):值可以是其中任一类型 → “或”关系 -
交集类型(
Loggable&Cacheable):值必须同时是所有类型 → “且”关系 -
泛型(如
Collection<User>):PHP 8.3 仍不支持原生泛型语法,交集类型不能替代它
交集类型无法表达“数组里全是某类对象”,那种需求目前仍需靠文档注释(PHPDoc)或静态分析工具(如 PHPStan)配合 @var User[] 来保障。
注意事项与避坑点
交集类型虽强,但有硬性限制:
- 不能包含
mixed、never、void或标量类型 - 不能出现两个 final 类(因无法同时继承)
- 类与接口组合时,类必须显式实现该接口,否则类型检查失败
- 在构造函数参数、返回值、属性、函数参数中均可使用,但不支持在数组键或 foreach 中直接解构
它不是银弹,适合明确契约的协作层(如插件系统、中间件接口、策略对象),不适合松散的数据容器场景。



















