array_merge_recursive() 会将重复键的标量值自动包裹成数组,因其设计目标是递归合并而非覆盖;而 array_merge() 虽不打包但不递归,会丢失深层结构;可用 array_replace_recursive() 或自定义函数避免标量被包裹。

PHP 合并嵌套数组时,标量值被自动包进数组,通常不是“合并操作”本身导致的,而是你用了像 array_merge_recursive() 这类函数,它对同名键的处理逻辑就是:遇到标量值(如字符串、数字),就把它转成数组再合并,而不是覆盖或丢弃。
array_merge_recursive() 的默认行为
这个函数设计目标是“递归合并”,不是“覆盖式合并”。当两个数组都有键 'name',一个值是 'Alice'(字符串),另一个是 'Bob',它不会选一个、丢一个,也不会报错,而是把两个都保留——方式就是把它们都放进一个新数组里:['Alice', 'Bob']。
- 如果原先是
['user' => 'Alice']和['user' => 'Bob'],合并后变成['user' => ['Alice', 'Bob']] - 哪怕只有一个标量,比如
['data' => 42]和['extra' => 'ok'],只要没冲突,各自照常;但一旦键重复且任一为标量,就会触发“包裹进数组”逻辑
为什么不用 array_merge()?
array_merge() 遇到相同字符串键时,后面的会直接覆盖前面的,不会打包。但它不递归:嵌套数组会被整个替换成新数组,深层结构丢失。
- 例如:
['a' => ['x'=>1]]和['a' => ['y'=>2]]用array_merge()合并 →['a' => ['y'=>2]](x 消失) - 而
array_merge_recursive()会得到['a' => ['x'=>1, 'y'=>2]],看起来更“智能”,但代价是标量变数组
想保留标量不被包裹?换方法
没有内置函数能“既递归合并又不打包标量”,但你可以手动控制:
立即学习“PHP免费学习笔记(深入)”;
- 用
array_replace_recursive():它对标量是“后覆盖前”,不打包;只对数组才递归合并 - 自己写递归函数,判断
is_array()再分支处理,对标量直接赋值,对数组才调用自身 - 如果只是想合并配置,考虑用
+数组合并运算符(左优先,不递归,但简单干净)
常见误用场景
很多人在读取多个 YAML/JSON 配置文件后,直接 array_merge_recursive($a, $b),结果发现 'debug' => true 变成了 'debug' => [true],后续 if ($cfg['debug']) 仍为真,但类型变了,某些严格校验或序列化场景会出问题。
不复杂但容易忽略



















