PHP 8.3 修复了数组解包丢失字符串键的问题,此前版本(含8.2)会强制转为索引数组,8.3+ 保留原键;升级后需检查依赖键丢失逻辑的代码,并显式控制键的保留或丢弃。

PHP 8.4 并没有改变数组解包([...$array])的行为——真正修复这个行为的是 PHP 8.3。
PHP 8.3 才真正修复了数组解包丢失字符串键的问题
很多人误以为是 8.4 改的,其实是 8.3(2023 年 11 月发布)首次让解包保留字符串键。此前所有版本(包括 8.2 及更早)中,[...$array] 会把关联数组强制转为索引数组,丢掉所有字符串键。
- PHP 8.2 及以前:
[...'a' => 1, 'b' => 2]→[1, 2](键丢失) - PHP 8.3+:
[...'a' => 1, 'b' => 2]→['a' => 1, 'b' => 2](键保留)
这个变化不是“新增特性”,而是对语言一致性的修复:既然 array_merge() 和函数参数解包(fn(...$args))早就支持字符串键,解包语法理应保持语义统一。
升级到 PHP 8.3+ 后,哪些代码要立刻检查
如果你之前靠“解包必丢键”来实现某种逻辑(比如故意抹平键名做扁平化),现在会意外保留键,导致行为不一致。
立即学习“PHP免费学习笔记(深入)”;
- 用
[...$arr]做“去重 + 重排索引”的场景:现在不会重排了,需显式用array_values([...$arr]) - 依赖
foreach ([...$arr] as $v)总是拿到数字索引:现在可能拿到字符串键,is_int(key($v))判断会失效 - 单元测试里 mock 了“解包后键消失”的断言:需要更新预期值,否则测试直接 fail
跨版本兼容写法:想丢键 or 想保键都得显式控制
不要依赖版本差异隐式行为。明确意图,才能避免在 8.3/8.4 环境下出问题。
- 想**强制丢键、只留值**:用
array_values([...$arr])或array_merge([], ...$arrays) - 想**安全保键、兼容老版本**:别用解包,改用
array_merge($arr1, $arr2)(它从 PHP 5 就保留字符串键) - 想**判断当前是否支持键保留**:可检测
version_compare(PHP_VERSION, '8.3.0', '>='),但更推荐直接写确定行为的代码
最常被忽略的一点:很多团队升级到 8.4,却没意识到解包行为其实在 8.3 就变了;如果跳过 8.3 直接从 8.2 升 8.4,这个问题会集中爆发,且错误现象分散(比如 API 返回结构突变、数据映射错位),排查成本远高于早期适配。



















