联合类型必须严格遵循语法规范:禁止void/mixed/never参与,不可混用?前缀与|null,null须显式声明;参数、返回值及php8.1+属性均支持,但需避免非法组合如string&array,否则触发fatal error。

联合类型怎么写才不会触发 fatal error
PHP 8.0+ 的联合类型不是“随便写几个类型用 | 连起来就行”,它有明确的语法限制和运行时校验逻辑。写错会直接抛出 Fatal error: Union type cannot contain nullable type 或类似错误。
常见踩坑点:
-
?string和string|null看似等价,但 PHP 8.0 不允许在联合类型中混用可空语法 —— 必须统一用string|null,不能写成?string|int -
void、mixed、never不能出现在联合类型中(mixed是独立类型,不是联合) - 标量类型与复合类型可混合(如
int|array),但两个对象类型不能直接联合(DateTime|stdClass合法,但DateTime|DateTimeImmutable在某些旧补丁版本中曾有兼容问题,建议实测) - 函数参数声明为
string|array,传入null仍会报错 —— 联合类型不自动包含null,需显式写成string|array|null
交集类型只能用于接口组合?
PHP 8.1 的交集类型(&)确实不支持标量或数组之间的交集,但它比“只能接口”更宽泛:只要其中一个是对象类型(类或接口),另一个是接口,就合法。
典型可用组合:
-
Logger & Serializable(两个接口) -
MyService & Cacheable(类 + 接口) -
stdClass & JsonSerializable(内置类 + 接口)
但这些写法会报错:
-
string & array→Fatal error: Intersection types may only contain object types -
int & string→ 同上 -
array & Traversable→array不是对象类型,非法
注意:array 是语言结构,不是类,所以不能参与交集;若需约束“既是数组又可迭代”,应改用 Traversable|array 联合类型 + 运行时检查。
联合类型 + 交集类型一起用的实战场景
真实业务中,常需要“某个值是 A 或 B 类型,且必须同时满足 X 和 Y 行为”——这时就得嵌套使用。比如日志处理器既要接受多种输入格式(联合),又要确保具备序列化与上下文注入能力(交集)。
示例:
interface Loggable {
public function log(string $msg): void;
}
interface ContextAware {
public function withContext(array $context): static;
}
interface Serializable {
public function serialize(): string;
}
// 处理器接收:字符串|数组|实现了 Loggable & Serializable 的对象
function handleLog(
string|array|Loggable&Serializable $input,
ContextAware&Loggable $logger
): void {
if (is_string($input) || is_array($input)) {
$logger->log(json_encode($input));
} else {
$logger->log($input->serialize());
}
}
关键点:
- 参数
$input是联合类型,覆盖简单数据和富对象两种路径 - 参数
$logger是交集类型,强制要求调用者传入一个既可记日志、又能携带上下文的对象 - IDE(如 PHPStorm 2025.1+)能据此推导出
$input->serialize()只在对象分支下可用,避免误提示
类型声明变复杂后,IDE 和静态分析工具跟得上吗
联合/交集类型对工具链有明确要求:PHPStan 1.10+、Psalm 5.20+、PHPStorm 2024.3+ 才能完整识别 string|int|null 或 A&B&C 这类声明。老版本可能只认第一个类型或直接忽略。
影响实际开发的细节:
- PHPStan 默认 level 5 不检查交集类型的实现完整性,需升级到 level 8 并启用
checkIntersectionTypes配置项 - Psalm 对
array|string的count()调用会警告“Possibly invalid argument”,因为count(string)在 PHP 8.0+ 已废弃 —— 这反而是类型系统帮你提前暴露了潜在 bug - 如果项目还混用 PHP 7.4 的
??或??=操作符,联合类型变量参与空合并时,PHP 8.0+ 会按左侧类型推导,但 Psalm 可能误报“Redundant condition”,需加注解@psalm-var string|int
最易被忽略的一点:类型声明再精确,也无法替代对运行时值的结构验证。比如 array|string 允许传入 ["foo" => new DateTime()],但下游 json_encode() 仍可能失败 —— 联合类型管的是“传进来是什么”,不是“里面装了什么”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











