
array_merge 合并时,键名冲突到底怎么处理
关联数组的字符串键遇到重复,后一个值直接覆盖前一个;索引数组的数字键会被重排,不保留原位置。这不是 bug,是 PHP 的明确设计——array_merge 本质是“重建索引 + 覆盖同名键”,不是“逐项叠加”。
常见错误现象:array_merge(['a' => 1], ['a' => 2]) 返回 ['a' => 2],而不是 ['a' => [1, 2]];又比如 array_merge([10, 20], [30, 40]) 得到 [0 => 10, 1 => 20, 2 => 30, 3 => 40],不是 [10, 20, 30, 40](这个看起来一样,但注意:如果第一个数组带非连续数字键如 [5 => 'x'],结果会从 0 开始重排)。
- 想保留原数字键?用
+运算符,但只对**左侧缺失的键**生效,右侧同名键不会覆盖 - 想合并同名键的值为数组?得自己写逻辑,
array_merge不干这事 - PHP 8.1+ 对空数组或 null 的处理更严格,传
null会报TypeError,别直接丢变量进去
关联数组和索引数组混用时,数字键自动转成索引的真相
array_merge 只认“是否为整数键”,不区分你主观认为它是“索引”还是“ID”。只要键是整数(哪怕写成 0123),就按索引数组规则处理:清空原有数字键,从 0 开始重新编号。
使用场景:读取数据库返回的混合结构(比如 PDO 默认 PDO::FETCH_BOTH 产生同时含数字和字符串键的数组),再用 array_merge 拼接时,你会发现数字键全没了。
立即学习“PHP免费学习笔记(深入)”;
-
array_merge(['name' => 'A'], [0 => 'X', 1 => 'Y'])→['name' => 'A', 0 => 'X', 1 => 'Y'] -
array_merge([0 => 'X'], ['id' => 123])→[0 => 'X', 'id' => 123],没问题 - 但
array_merge([5 => 'X'], [10 => 'Y'])→[0 => 'X', 1 => 'Y'],原键 5 和 10 彻底消失
替代方案:什么时候该用 + 而不是 array_merge
+ 是数组联合运算符,行为和 array_merge 完全不同:它按“左操作数优先”保留所有键,只把右操作数中**左操作数没有的键**加进来,同名键绝不覆盖。
性能影响:两者都是 O(n),但 + 不做键重排,对大数组略快;兼容性上,+ 自 PHP 4 就存在,比 array_merge_recursive 更稳妥。
-
$a = ['a' => 1, 'b' => 2]; $b = ['b' => 3, 'c' => 4]; $a + $b→['a' => 1, 'b' => 2, 'c' => 4] -
[0 => 'x'] + [0 => 'y', 1 => 'z']→[0 => 'x', 1 => 'z'](右边的 0 被忽略,1 加进来) - 注意:
+不递归,嵌套数组照样按键覆盖/跳过,不会合并子数组
array_merge_recursive 真的能“递归合并”吗
它只对**同名且同为数组的值**做递归,其他情况照旧覆盖。所以 array_merge_recursive(['a' => 1], ['a' => 2]) 还是 ['a' => 2],不是 ['a' => [1, 2]];只有两边 a 都是数组时,才真正递归。
容易踩的坑:以为它能解决“同名键值合并为数组”的需求,结果发现根本没触发递归逻辑——因为原始值不是数组类型。
-
array_merge_recursive(['a' => [1]], ['a' => [2]])→['a' => [1, 2]] -
array_merge_recursive(['a' => 1], ['a' => [2]])→['a' => [2]](整数被数组覆盖) - 真要实现“所有同名键都转成数组”,得先统一类型,或用
array_reduce手动聚合
最常被忽略的一点:array_merge 对 null、false、未定义变量会直接报错或静默失败,传参前必须确保每个参数都是数组类型,用 is_array() 或 (array) 强转兜底。











