PHP 8.0 中 int 不被 string|null 接受,因联合类型严格匹配、不隐式转换;须显式转为 string 或 null,如 safeToString($value)。

直接传 int 给声明为 string|null 的参数,PHP 8.0 会立即抛出 TypeError —— 这不是 bug,是联合类型校验的正常行为。你必须让传入值严格落在 string 或 null 范围内。
为什么 int 不被 string|null 接受?
PHP 的联合类型是“精确匹配”,不自动做隐式类型转换。即使 (string)42 是合法字符串,42 本身仍是 int,不在 string|null 的可选集合中。
-
string|null表示“只能是字符串,或者 null” -
int、float、bool、array等都不属于该集合 - 哪怕值语义上能转成字符串(如
42→"42"),运行时也不会帮你转
常见错误调用场景和修复方式
这类错误多出现在从数据库、API 或表单取值后未做类型适配就直传函数的情况。
- 错误写法:
logMessage($user['id']),其中$user['id']是int - 正确做法:显式转换或提前判断
logMessage($user['id'] === null ? null : (string)$user['id']) - 更安全的封装:
function safeToString($value): ?string { return $value === null ? null : (string)$value; }
再调用logMessage(safeToString($user['id']))
string|null 和 int|string|null 的性能与语义差异
加一个 int 进去看似“宽松”,实则改变契约含义,且有隐藏成本:
立即学习“PHP免费学习笔记(深入)”;
-
string|null:明确表达“只接受字符串或空”,IDE 和 PHPStan 能据此推断后续逻辑无需处理数字分支 -
int|string|null:类型检查开销略增(需逐个比对),更重要的是——调用方无法再假设输入一定是字符串,后续所有字符串操作(如strlen()、正则匹配)都得先判断类型 - 若业务本意就是“字符串 ID”,但数据库字段是
INT,建议在数据层统一转为string,而非在类型声明里妥协
declare(strict_types=1) 对联合类型的影响
无论是否开启严格模式,string|null 都不会接受 int。但严格模式会让错误更早暴露:
- 开启
declare(strict_types=1):传int直接报TypeError,不执行函数体 - 未开启:部分内置函数(如
strlen(null))仍可能做隐式转换,但用户函数仍按联合类型规则校验 —— 所以别依赖非严格模式“绕过”类型检查 - PHP 8.1+ 已废弃向非 null 参数传
null的行为,同理,也绝不鼓励靠关闭严格模式来掩盖类型不匹配
最易被忽略的一点:联合类型校验发生在函数入口,不看你函数体内有没有 is_int() 或 strval()。想“兜底”就只能在调用前转换,或改用更宽泛但语义清晰的联合类型(比如确认要支持数字,就明确定义为 string|int|null,而不是指望运行时自动适配)。



















