array_replace_recursive是最简方案但功能有限,仅递归替换不支持合并数组值、跳过空值或处理循环引用;需自定义deepMerge函数实现按需控制逻辑。

array_replace_recursive 是最简方案,但行为不总是你想要的
它确实能递归处理嵌套结构,比如 $m = ['user' => ['name' => 'A', 'age' => 20]] 和 $n = ['user' => ['age' => 25, 'city' => 'Beijing']] 合并后,user.age 被更新,user.city 被新增。但它只做“替换”,不支持“合并数组值”或“跳过空值”。如果某个子键是 null 或空数组,它会原样覆盖,不会跳过。
常见误用点:
- 传入非数组值(如字符串、数字)给
array_replace_recursive会静默失败,返回原数组 - 若想保留左侧非空值、仅用右侧非空值覆盖,它做不到——得自己加判断
- 它不处理循环引用,遇到自引用数组会崩溃
自定义 deepMerge 函数才能真正按需控制逻辑
标准函数做不到的,比如“同键是数组才递归,否则直接覆盖”“跳过 null 或空字符串”“对数值键做追加而非覆盖”,就得手写。核心是:只在双方都是数组时递归,其余一律以右侧为准。
示例关键逻辑:
立即学习“PHP免费学习笔记(深入)”;
- 遍历
$array2的每个$key => $value - 若
$value是数组,且$array1[$key]存在且也是数组,则调用自身:$array1[$key] = deepMerge($array1[$key], $value) - 否则直接赋值:
$array1[$key] = $value - 最后返回
$array1
这种写法避免了 array_merge_recursive 把字符串键值强行包成数组的副作用,也比 array_merge 更安全地维持层级。
合并多个数组时别硬套 array_merge_recursive
array_merge_recursive 支持多参数,但它的“递归合并”语义是把所有同名键的值塞进一个数组里。例如两个数组都有 'tags' => ['php'] 和 'tags' => ['web'],结果是 'tags' => [['php'], ['web']],而不是扁平的 ['php', 'web']。这通常不是你想要的。
更实用的做法:
- 用
func_get_args()收集所有数组,再用循环调用自定义deepMerge - 若需去重合并(如 tags),先用
array_merge扁平化所有tags子数组,再用array_unique处理 - 避免在循环中反复修改第一个数组,建议用引用或新建容器累积结果
递归深度大时要注意 PHP 栈限制和性能
PHP 默认递归限制约 100 层,超了会报 Fatal error: Maximum function nesting level。多维数组嵌套深(比如解析大型 JSON 配置树)时容易触发。
缓解方式:
- 加深度计数器,在递归调用前判断
$depth > 50就提前退出或抛异常 - 改用栈模拟递归(while + array_pop),完全避开函数调用栈
- 对纯数据聚合场景(如求和、计数),优先用
array_walk_recursive扁平化再处理,比层层递归快得多
真正难的不是写递归,而是判断哪一层该停、哪一层该合并、哪一层该丢弃——这些边界逻辑,必须贴着业务字段来定,没法靠通用函数兜底。



















