php 8.0联合类型是声明即生效的运行时约束,参数/返回值必须严格匹配int|string等联合类型,不接受隐式转换;属性联合类型需php 8.1+,8.0中须用@var注释+setter兜底,且strict_types=1非必需但推荐。

PHP 8.0 的联合类型(Union Types)不是“调用时特殊处理”的功能,而是**声明即生效的运行时类型约束**——函数一旦用 int|string 声明了参数或返回值,PHP 解释器会在调用/返回瞬间做严格校验,不接受隐式转换,也不提供额外“调用语法”。你照常传参、接收返回值,但必须确保类型匹配。
函数参数联合类型怎么传值才不报 TypeError
声明为 function handle(int|string $id) {} 后,传参必须是 int 或 string 的纯值,PHP 不会帮你 cast 或 fallback:
-
handle(42)✅ 合法 -
handle("abc")✅ 合法 -
handle("123")✅ 合法(字符串字面量,不是数字字符串自动转 int) -
handle(123.5)❌ 报Fatal error: Uncaught TypeError,float 不在联合范围内 -
handle(null)❌ 即使你本意是“可空”,int|string不含null,必须显式写成int|string|null或?int|string(后者非法,见下条)
注意:?int|string 是无效语法 —— ? 只能修饰单个类型,等价于 int|null|string 的写法也非法;正确可空联合只能是 int|string|null。
返回值联合类型为什么 return "42" 会挂掉
函数声明为 function getId(): int|string,表示“返回值必须是 int 或 string”,但 PHP 对返回值的校验比参数更激进:它不做任何隐式类型转换,哪怕值语义上可转也不行。
-
return 42;✅ -
return "42";✅ -
return "42" + 0;❌ 返回 int,但表达式本身是 string 运算,实际执行可能触发 warning,且类型推导不稳定 -
return (int)"42";✅ 显式转换后是 int,符合声明 -
return $_GET['id'] ?? 0;❌ 若$_GET['id']是字符串,??会原样返回,但若值是"abc",则"abc" ?? 0返回"abc"(合法),而若值是"",则返回0(也合法)——看似安全,实则依赖输入质量,不推荐靠数据源“碰运气”满足联合类型
关键点:返回值联合类型是**出口守门员**,只认最终 return 表达式的运行时类型,不看中间逻辑。
PHP 8.0 属性不能直接用联合类型声明
这是最容易踩的坑:你写 public int|string $id; 会直接触发 ParseError: Syntax error, unexpected token "string"。PHP 8.0 **仅支持联合类型用于函数参数、返回值、静态变量**,类属性(instance property)要到 PHP 8.1 才放开。
- PHP 8.0 中唯一合规写法是用
@var注释:/** @var int|string */ public $id;
它不影响运行,但能让 PHPStan / Psalm / PhpStorm 知道语义,并在赋值时提示错误(如$user->id = [];) - 若需运行时防护,必须收口到 setter:
public function setId(int|string $id): void { $this->id = $id; }靠方法参数的联合类型兜底 - 别混用:如果已用
int|string声明了参数,就别再加@param int|string $id—— PHPStan 会警告 redundant PHPDoc
版本混淆是高频问题:看到教程里 public int|string $prop; 能跑,大概率对方用的是 PHP 8.1+,而你卡在 8.0 就只能靠注释 + setter 组合拳。
联合类型和 strict_types=1 是什么关系
联合类型本身**不依赖** declare(strict_types=1),它在弱类型模式下也强制生效。但两者叠加时,行为更“干净”:
- 没开
strict_types=1时,function foo(int|string $x) {}接收"123"没问题,但接收123.5仍报错(因为 float 不在联合中) - 开了
strict_types=1后,连"123"传给int参数都会报错 —— 但这里联合类型已覆盖该行为:只要"123"匹配string分支,就允许,不受 strict mode 影响 - 真正被 strict mode 放大的是“非联合场景”:比如你漏写了联合,只写了
int,那 strict mode 会让字符串数字直接失败;而联合类型的存在,恰恰是为了避免这种窄声明带来的脆弱性
所以不必为联合类型专门开 strict mode,但项目里统一开启仍是好习惯 —— 它让所有类型边界更清晰,包括联合类型内部的每个分支。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











