array_merge() 总覆盖同名字符串键因其“后数组优先”设计,如 ['name'=>'A'] 和 ['name'=>'B'] 合并结果为 ['name'=>'B'];数字索引则重编号不覆盖;需左优先时用+运算符,深层嵌套用 array_merge_recursive(),复杂逻辑应手动遍历处理。

array_merge() 为什么总覆盖同名键
因为 array_merge() 的设计就是“后数组优先”:遇到相同字符串键时,后面传入的数组值直接替换前面的。比如 array_merge(['name' => 'A'], ['name' => 'B']) 结果一定是 ['name' => 'B'],没有协商余地。
这在补全配置、合并 API 响应时极易出错——你以为在“叠加”,实际在“覆盖”。
- 仅对关联数组(字符串键)生效覆盖逻辑;数字索引会被重新编号,不涉及覆盖问题
- 若你希望保留左侧值、只补充缺失项,
array_merge()不是正确工具 - 调试时可先用
array_keys($arr1)和array_keys($arr2)对比键名,快速定位冲突点
用 + 运算符实现左优先合并
+ 运算符的行为和 array_merge() 完全相反:它保留左侧数组所有键值,右侧只插入左侧不存在的键。适合默认配置 + 用户配置这类场景。
例如:$defaults = ['timeout' => 30, 'retries' => 3]; $user = ['retries' => 5, 'log_level' => 'debug']; $config = $defaults + $user; → ['timeout' => 30, 'retries' => 3, 'log_level' => 'debug'],retries 没被覆盖。
立即学习“PHP免费学习笔记(深入)”;
- 注意:
+不会递归处理嵌套数组,['a' => ['x'=>1]] + ['a' => ['y'=>2]]结果仍是['a' => ['x'=>1]],子数组整体被跳过 - 不能用于索引数组合并(如
[1,2] + [3,4]只返回[1,2]),仅适用于关联数组 - 若右侧有
null或空字符串等“假值”,+仍会跳过——它只看键是否存在,不判断值真假
深层嵌套键需要 array_merge_recursive()
当你要合并的数组里还有数组(比如 ['user' => ['name'=>'A']] 和 ['user' => ['email'=>'a@b.com']]),array_merge() 会把整个 user 替换掉,而 array_merge_recursive() 会把两个 user 数组合并成 ['user' => ['name'=>'A', 'email'=>'a@b.com']]。
- 但它也有副作用:相同键的非数组值会被转成数组,比如
['id'=>1] + ['id'=>2]用array_merge_recursive()得到的是['id' => [1, 2]],不是你想要的覆盖或跳过 - 如果结构深度不确定,建议先用
is_array()判断再决定是否递归调用,避免意外生成多维数组 - 合并后若需扁平化结果(比如取第一个非空值),可用
array_filter()或array_values()配合current()提取
真正可控的合并得靠手动遍历
业务规则复杂时(比如“顶层键取第一个,data 子数组要合并,http_status 必须一致,否则报错”),硬套内置函数反而容易翻车。写个简单循环几行就能搞定:
$result = $arr1;
foreach ($arr2 as $key => $value) {
if ($key === 'data') {
$result['data'] = array_merge($result['data'] ?? [], $value);
} elseif ($key === 'http_status') {
if ($result[$key] !== $value) {
throw new InvalidArgumentException('http_status mismatch');
}
} else {
$result[$key] = $value; // 或 $result[$key] = $result[$key] ?? $value;
}
}
- 关键点在于:不要假设所有键都适用同一规则。顶层状态字段(
success、message)往往只需校验一致性,而非合并 - 用
$result[$key] ?? $value替代无条件赋值,可避免覆盖已有有效值,比??=更灵活(后者只能用于变量,不能用于数组下标) - 最容易被忽略的是 null 值穿透——比如
$arr2['data']是null,直接array_merge($result['data'], $arr2['data'])会报 warning,务必先判空



















