PHP 8.1 起标量类型参数(如 string、int、bool)不再接受 null,会直接抛 TypeError;因 PHP 统一了内置与用户函数的类型检查逻辑,废除旧版静默转换(null→''/0/false),强制显式处理空值以暴露逻辑缺陷。

PHP 8.1 起,把 null 传给标量类型参数(如 string、int、bool)会直接报 TypeError,不再静默转成默认值。这不是警告,是运行时错误,业务直接崩。
为什么 PHP 8.1 突然不兼容了?
PHP 8.1 统一了内置函数和用户函数的类型检查逻辑:标量类型参数默认不再接受 null,除非你显式声明为可为空(?string、?int)。此前 PHP 7.x 和 8.0 会把 null 自动转成 ''、0、false —— 这种“宽容”掩盖了大量空值逻辑缺陷。
典型触发点:
- 数据库字段为 NULL,直接塞进
strlen($name)或date('Y-m-d', $created_at) - API 请求没传某个字段,但控制器方法签名写的是
public function update(string $title) - ThinkPHP 的
where()条件数组里混入了未判空的$status,而它实际是null,最终被传进array_merge或自定义校验函数
修复核心:别依赖自动转换,显式处理 null
所有可能为 null 的变量,在进入标量类型参数前必须做判断或转换。不能靠函数自己“兜底”。
立即学习“PHP免费学习笔记(深入)”;
- 用联合类型声明参数:
function process(?string $name): void,然后在函数内加if ($name === null) { ... } - 调用前主动转换(仅限语义安全场景):
strlen((string) $name)或intval($id),但要注意(string) null得'',intval(null)得0,是否符合业务逻辑? - 用空合并操作符提供默认值:
process($name ?? '未知'),比三元更简洁,且只在null或undefined时生效 - 数据库查询层统一加
COALESCE或 ORM 映射时设默认值(如 Laravel 的$casts或 ThinkPHP 的default属性)
array_merge() 报 Argument #1 must be of type array, null given 怎么快速定位?
这是 PHP 8.1 下最常炸的点,尤其在 ThinkPHP 6.0.13 及更早版本中高频出现。错误不是出在 array_merge 本身,而是你传进去的第一个参数是 null。
- 搜索项目中所有
array_merge(调用,重点检查形如array_merge($a, $b)的地方,其中$a或$b是否来自数据库字段、$_GET、input()或未初始化变量 - 立刻加守卫:
array_merge($a ?? [], $b ?? [])或is_array($a) ? $a : [] - ThinkPHP 中特别注意:
where()数组、with()关联配置、自定义scope方法里的条件拼接 —— 这些地方最容易漏判空 - 不要写
array_merge([], $data)就以为安全,如果$data是null,照样报错
容易被忽略的隐式陷阱
有些转换看着不明显,但 PHP 8.1 同样拒绝:
-
foreach ($items as $item)中,$items是null→ 直接Invalid argument supplied for foreach() -
json_encode($data)传入null虽然合法,但若$data是对象且属性为null,而你又在 getter 里写了return (string) $this->name;,那这里就炸了 -
printf('%s', $name)中$name为null→TypeError: printf(): Argument #2 ($values) must be of type string, null given - 用
??时误写成?::前者只对null和undefined生效,后者还会对0、false、''生效,导致逻辑偏移
真正麻烦的从来不是报错本身,而是那些没报错、却因旧版自动转换悄悄跑偏的业务逻辑——比如订单状态字段为 null,被转成 0 后进了“已取消”分支。这类 bug 必须靠类型声明 + 显式判空 + 全链路数据流审计来堵住。



















