array_merge()对数字键重置索引是设计行为而非bug:它将整型键视为无意义占位符,统一重排为0起始连续整数;字符串键则保留并覆盖,体现“值拼接”语义,与“键合并”的+运算符本质不同。

PHP 的 array_merge() 在遇到数字索引(即整型键)时重置索引,不是 bug,而是函数设计的**明确行为**——它把所有数字键视为“无意义的顺序占位符”,统一重排为从 0 开始的连续整数。
底层原因:PHP 数组本质是有序哈希表,但 array_merge 对 int 键做了语义降级
PHP 数组底层是 HashTable,支持混合键类型。但 array_merge() 在实现中对键类型做了区分处理:
- 遇到字符串键(
'id'、'name'),认为有业务含义,保留键名,冲突时用后值覆盖前值 - 遇到整数键(
0、1、5),不视作“位置标识”,而当作“未显式指定键的默认索引”——哪怕你写了[2 => 'b'],只要它是 int 类型,就触发重排逻辑 - 内部遍历所有输入数组,把所有 int 键对应的值暂存进一个临时列表,最后一次性按顺序赋予
0, 1, 2, ...新键
为什么不是保留原数字键?设计哲学决定的
这个行为源于早期 PHP 对“索引数组”的定位:它代表一组**顺序数据**,而非稀疏结构。所以:
-
array_merge([2 => 'a'], [0 => 'b'])的结果是[0 => 'a', 1 => 'b'],因为合并意图是“拼接两段序列”,不是“映射两块内存地址” - 如果允许保留
2和0,结果会是稀疏数组[0 => 'b', 2 => 'a'],这违背了“合并即追加”的直觉 - PHP 没有提供“是否重排”的开关参数,是因为设计者认为:需要保留稀疏 int 键的场景,本就不该用
array_merge
对比 + 运算符:它不重排,是因为语义完全不同
+ 是“键合并”操作,不是“值拼接”:
立即学习“PHP免费学习笔记(深入)”;
- 它逐个检查左侧数组的键,存在就跳过右侧同键;不存在才把右侧键值加入
- int 键也被当作普通键对待,不会被特殊处理或降级
- 所以
[2 => 'a'] + [0 => 'b']结果是[2 => 'a', 0 => 'b'],顺序也按左→右,不重排
实际影响:哪些情况会意外触发重排?
容易被忽略的“隐式 int 键”场景:
- 数组字面量中省略键:
['a', 'b']等价于[0 => 'a', 1 => 'b']→ 必然重排 - 使用
array_values()后再 merge:array_merge(array_values($a), $b)→ 强制变成索引数组再重排 - JSON 解码后的数字索引:
json_decode('[{"x":1}]', true)返回[0 => ['x'=>1]]→ 参与 merge 就重排



















