array_merge(...$arr)可一键展开二维数组为一维,但要求子项全为数组且PHP≥5.6;含非数组元素会警告,非数字键会被重置;需保键名应改用$flat += $sub循环合并;深层嵌套须递归处理。

直接用 array_merge(...$arr) 会报错
很多人看到“二维转一维”第一反应是 array_merge(),但直接写 array_merge($arr) 没用——它只合并**传入的多个数组参数**,而你传的只是一个二维数组变量。更常见的是写成 array_merge($arr[0], $arr[1], ...),手动展开,但这不通用,且遇到空子数组或非数字键会出问题。
真正能“一键展开”的写法是**展开运算符 + array_merge()**:
$flat = array_merge(...$arr);
前提是:$arr 的每个子元素都必须是数组。如果其中混有字符串、数字或 null,PHP 会报 Warning: array_merge(): Argument #1 is not an array。
- ✅ 适用场景:所有子项确定为数组(如
[ ['a'], ['b','c'], ['d'] ]) - ⚠️ 坑点:PHP 版本必须 ≥ 5.6(支持展开运算符)
- ⚠️ 坑点:子数组含非数字键时,
array_merge()会重置键名(例如['x'=>1]变成[0=>1]),若需保留键,不能用此法
要保留键名?用 foreach 手动合并
当子数组有有意义的字符串键(比如 ['user_id'=>123, 'name'=>'Alice']),又不想被 array_merge() 重置,就得绕过自动合并逻辑。
立即学习“PHP免费学习笔记(深入)”;
最稳的方式是遍历并逐个 + 合并(注意:+ 是键名保留的左侧优先合并):
$flat = [];
foreach ($arr as $sub) {
if (is_array($sub)) {
$flat += $sub;
}
}
- ✅ 键名不丢失,重复键以第一个出现的值为准
- ✅ 兼容 PHP 5.3+,无版本限制
- ⚠️ 注意:如果子数组之间有相同字符串键(如都含
'id'),后面的会被忽略——这是+的行为,不是 bug - ⚠️ 如果需要“后面覆盖前面”,改用
$flat = array_replace($flat, $sub)
嵌套更深怎么办?得递归,别硬套 array_merge(...$arr)
array_merge(...$arr) 只能“摊平一层”。如果数组是三维甚至带混合结构(比如 [ [1, [2,3]], 4 ]),它完全无效,结果可能出人意料甚至报错。
这时必须明确需求:
- 只要“最外层子数组”的所有元素拉成一维?→ 还是用
array_merge(...$arr),但先array_filter($arr, 'is_array')清掉非数组项 - 要彻底打散所有层级(不管几维)?→ 必须写递归函数或用
iterator_to_array()配合RecursiveIteratorIterator
简单递归示例(兼容键名,不重置):
function array_flatten($arr) {
$result = [];
foreach ($arr as $item) {
if (is_array($item)) {
$result = array_merge($result, array_flatten($item));
} else {
$result[] = $item;
}
}
return $result;
}
这个函数对 [1, [2, [3, 4]], 5] 返回 [1,2,3,4,5],但会丢键名。若需保键,逻辑要更复杂——通常意味着你其实不该“强行扁平”,该重新审视数据结构设计。
性能和边界情况比想象中敏感
小数组无所谓,但处理上千个子数组时,array_merge(...$arr) 实际上会把整个数组复制进参数列表,PHP 内部有参数数量上限(默认约 1000+,视配置而定),超了就报 Too many arguments。
- ✅
foreach方案无参数限制,适合大数组 - ⚠️
array_merge(...$arr)在 PHP 8.0+ 有优化,但依然建议子数组数 - ⚠️ 空数组
[]或全非数组项传给array_merge(...$arr),会变成array_merge()无参数调用,返回空数组——这看似合理,但容易掩盖数据异常
真正在生产环境用,别只看“一行解决”,先 var_dump(array_filter($arr, 'is_array')) 看清楚输入结构再说。











