PHP默认合并函数无法实现同键数组追加,需手动递归:同为数组则递归合并,左数组右非数组则追加元素,左非数组右数组则包装后合并,否则覆盖。

PHP 合并多维数组时,如果键相同,默认的 array_merge 或 + 运算符会**覆盖**(后者是右侧覆盖左侧)或**按索引重排**(前者对数字键重排、字符串键后出现的覆盖先出现的),无法实现“相同键值下的子数组追加合并”。要让相同键(尤其是字符串键)下对应的数组内容**追加而非覆盖**,需手动递归处理。
用 array_replace_recursive 不行?
array_replace_recursive 看似合适,但它对**同键的数组值仍会递归替换**,不是追加。例如:
$a = ['user' => ['id' => 1]];<br> $b = ['user' => ['name' => 'Tom']];<br> array_replace_recursive($a, $b); // 结果是 ['user' => ['id' => 1, 'name' => 'Tom']] ✅
这看起来像追加,但仅限于「键不重复」时自动合并;若两边都有
['user' => ['id' => 2]],则 id 会被覆盖,不是追加成数组。
真正实现“同键追加”的递归合并函数
核心逻辑:遇到两个同名键且值都是数组时,不替换,而是将右数组的元素逐个 [] = 追加到左数组中(保持原结构),其他情况照常替换或保留。
- 判断左右对应键的值是否都为数组 → 是则递归追加合并
- 若左值是数组、右值不是数组 → 把右值作为新元素追加进左数组(
$left[] = $right) - 若左值不是数组、右值是数组 → 通常视为错误或按需转为数组,常见做法是把左值包进数组再合并右数组
- 否则直接用右值覆盖左值(标准替换行为)
一个简洁可靠的实现示例
以下函数支持深度合并,并对同键数组自动追加元素(非覆盖):
// $a 是目标数组(被修改),$b 是待合并数组
function array_merge_append_recursive(&$a, $b) {
foreach ($b as $key => $value) {
if (isset($a[$key]) && is_array($a[$key]) && is_array($value)) {
array_merge_append_recursive($a[$key], $value);
} elseif (isset($a[$key]) && is_array($a[$key])) {
$a[$key][] = $value;
} elseif (isset($a[$key])) {
$a[$key] = [$a[$key], $value];
} else {
$a[$key] = $value;
}
}
}
使用示例:
立即学习“PHP免费学习笔记(深入)”;
$arr1 = ['users' => [['id' => 1, 'name' => 'Alice']]]; $arr2 = ['users' => [['id' => 2, 'name' => 'Bob']]]; array_merge_append_recursive($arr1, $arr2); // 结果:['users' => [['id'=>1,'name'=>'Alice'], ['id'=>2,'name'=>'Bob']]] ✅
更通用:返回新数组,不修改原数组
如需函数式风格(不修改输入),可改写为返回新数组:
- 用
array_merge_recursive前先预处理:把需追加的键(如'users')单独提取,用array_merge合并其值,再塞回结果 - 或封装一个带白名单的版本,只对指定键执行追加,其余走标准递归替换
- 实际项目中建议明确哪些键需要“追加语义”(如
logs、errors、items),避免无差别追加导致结构混乱



















