array_merge 会重排数字键是设计行为而非 bug,它强制将所有数字键重置为从 0 开始的连续整数,以确保逻辑拼接后的数组索引干净、可遍历;字符串键则按覆盖规则处理。

array_merge 会重排数字键,这是设计行为,不是 bug
array_merge 对含数字键(即索引数组)的输入,强制重新索引为从 0 开始的连续整数。这不是意外,而是 PHP 官方文档明确规定的语义:只要数组中存在数字键名,合并后所有数字键都会被丢弃并重排。
常见错误现象是:
- 你传入
$a = [10 => 'x', 20 => 'y']和$b = [30 => 'z'],期望结果保留原键; - 实际得到
[0 => 'x', 1 => 'y', 2 => 'z'],原键 10/20/30 全部消失。
这跟字符串键完全不同:字符串键冲突时是覆盖('name' => 'Alice' 被后面同名的 'name' => 'Bob' 替换),而数字键永远不“冲突”,只“追加 + 重排”。
为什么 array_merge 不保留数字键?
PHP 内部将“数字键是否有序”和“是否应视为列表”强绑定。当你用 array_merge,它默认你是在做「逻辑拼接」——比如把两个列表连成一个新列表,所以必须保证索引连续、可遍历、无空洞。
- 数字键在 PHP 中本质是“顺序位置标识”,不是“唯一 ID”;
- 如果允许保留稀疏数字键(如
[0, 1, 100 => 'x']),后续foreach或count()行为仍正常,但for ($i=0; $i<count> 就会漏掉元素; </count> - 所以
array_merge主动消除歧义:一律重排,确保结果是“干净索引数组”。
这也是它和 + 运算符的根本分歧点:+ 是“键优先合并”,array_merge 是“值优先拼接”。
想保留数字键?别用 array_merge
如果你明确需要维持原始数字键(比如配置项 ID、数据库主键映射、稀疏缓存索引),array_merge 不适合。
可用替代方案:
用
+运算符:$result = $a + $b;—— 保留左侧键,右侧仅补缺;但注意:若两侧都有相同数字键(如[0=>'a'] + [0=>'b']),右侧完全被忽略,0=>'a'保留。用
array_replace:array_replace($a, $b)对字符串键和数字键都按“右覆盖左”处理,且不重排数字键;但它也不会追加新数字键(只替换已有键),新增数字键会被丢弃。-
手动循环合并(最可控):
foreach ($b as $k => $v) { $a[$k] = $v; }这样既保留所有键(无论字符串或数字),又实现“右覆盖左”,且不触发任何隐式重排。
容易忽略的关键细节
- 单个数组调用
array_merge($arr)同样触发重排:哪怕只有一个参数,只要它是数字键数组,就会变成[0,1,2...]; - 混合键数组(如
['a'=>1, 0=>2, 1=>3])中,数字键部分仍被重排,字符串键照常覆盖; -
array_merge_recursive也不保留数字键——它只改变覆盖逻辑(改为合并成子数组),重排行为完全一致; - PHP 7.4+ 支持无参调用
array_merge(),返回空数组,但这个空数组是[](键从 0 开始),不是[0=>null]或其他。
数字键要不要重排,本质上是你在表达“这是列表”还是“这是带 ID 的映射”。选错函数,就等于误传了语义。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











