Menu

PHP array_merge():合并两个或多个数组

array_merge($a, $b) 把多个数组合并成一个:数字键的值会追加到末尾并重新编号,字符串键则以后面的数组为准。学习 array_merge 与 + 运算符、展开语法 [...$a, ...$b] 的区别,怎样合并一组数组,以及什么时候更适合用 array_merge_recursive 或 array_replace。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

array_merge($a, $b) 返回一个新数组,先是 $a 的元素,后面接着 $b 的元素。数字键会从 0 开始重新编号;当两个数组有相同的字符串键时,以后面数组中的值为准。你可以传入任意多个数组。

array_merge() 不会修改它的参数。它返回合并后的数组,所以要把结果赋值出去:$all = array_merge($all, $more);。

数字键会被重新编号

array_merge() 把整数键当作位置,而不是名字。每个整数键的元素都会被追加,并从 0 开始获得新的键,即使原数组用的是相同的数字或者键不连续。对于列表来说这正是你想要的,但当这些数字是 ID 时就会让你意外。

看起来像整数的字符串键('101')会被存储为整数,所以它们也会被重新编号。像 'id101' 这样的键则保持不变。

array_merge 与 + 运算符

+ 运算符(数组联合)也能合并数组,但规则正好相反:对于左边数组中已经存在的键,以左边的值为准,右边的值被丢弃。它从不重新编号。因此 + 最适合用来补全默认值,而 array_merge() 最适合用来覆盖默认值。

array_merge($a, $b)$a + $b
相同的字符串键取 $b 中的值取 $a 中的值
整数键重新编号,保留所有值保留键,冲突时丢弃 $b 的值
典型用途连接列表、覆盖设置补全默认值、保留 ID

代码块中的最后一个例子是经典的 + 陷阱:['a', 'b'] + ['x', 'y', 'z'] 得到的是 a, b, z,因为键 0 和 1 在左边已经存在。

展开语法:[...a,...a, ...b]

展开运算符在数组字面量中把数组展开。它的行为和 array_merge() 一样:整数键会重新编号;从 PHP 8.1 开始也允许字符串键,并以后面的为准。当你要把数组和单个值混在一起时,这种写法读起来很清楚。

如果要把一个数组直接追加到已有的数组上,请看 array_push() 配合展开运算符。

合并一个由数组组成的数组

当要合并的数组本身就放在一个列表里时,把这个列表展开传给 array_merge()。这也是在循环中合并的高效方式:先收集各个部分,再一次性合并。

在循环里写 $all = array_merge($all, $batch); 也能工作,但它每一轮都会复制整个不断变大的数组,元素有几千个时就会变慢。

array_merge_recursive 和 array_replace

array_merge_recursive() 也会合并嵌套数组,但对于保存普通值的重复字符串键,它不会覆盖,而是把两个值收集到一个新数组里。对于配置来说,这很少是你想要的。这种情况下通常该用 array_replace_recursive():它会在每一层覆盖值,并保留键。

从上到下看这三行 JSON:array_merge() 替换了整个 db 数组,丢失了 host;array_merge_recursive() 把 port 和 debug 变成了包含两个元素的列表;而 array_replace_recursive() 生成了你真正想要的配置。

常见错误:合并不会去掉任何东西

array_merge() 会保留位于不同键下的重复值。合并两个标签列表时,两者共有的每个标签都会出现两次。把结果先交给 array_unique(),再用 array_values() 重新编号。

array_unique 页面介绍了如何从多行数据和嵌套数组中去除重复项。

常见问题

PHP 中 array_merge 和 + 有什么区别?

对于重复的字符串键,array_merge($a, $b) 保留 $b 中的值,而 $a + $b 保留 $a 中的值。对于数字键,array_merge() 会把所有元素追加并重新编号,而 + 会保留数字键,并丢弃 $b 中键已经存在于 $a 的元素。

怎样合并数组并保留数字键?

如果应该以左边的数组为准,用 $a + $b;如果应该以右边的数组为准,用 array_replace($a, $b)。array_merge() 总是把数字键从 0 开始重新编号。

PHP 中怎样合并一个由数组组成的数组?

把外层数组展开传给 array_merge():$all = array_merge(...$lists);。列表为空时它返回 []。先在循环中收集各个数组,最后一次性合并;在循环里调用 array_merge() 每次都会复制不断变大的结果。

PHP 的展开运算符可以用于字符串键吗?

可以,从 PHP 8.1 开始。这时 [...$a, ...$b] 的行为和 array_merge($a, $b) 一样:数字键会重新编号,后面的字符串键会覆盖前面的。

Coddy 编程语言插图

和 Coddy 一起学编程

开始