优先用扩展运算符[...$arr]处理索引数组,性能更高;关联或混合数组必须用array_merge(),但需警惕其数字键重排问题;不确定输入类型时应先强制转换为数组再使用。

用 [...$arr] 还是 array_merge()?先看数组类型
扩展运算符([...$arr])只支持索引数组展开,遇到关联数组会直接报 Fatal error: Uncaught Error: Cannot use splat operator with string keys。而 array_merge() 天然支持关联数组,键冲突时按顺序覆盖——比如 ['a' => 1] 和 ['a' => 2] 合并后是 ['a' => 2]。
如果你的数组来自 json_decode($json, true)、数据库查询结果或明确含字符串键,别碰 [...$arr],它连解析都过不去。
- 索引数组(纯数字键):两个都能用,但
[...$arr]更快、更直观 - 关联数组(含字符串键):必须用
array_merge(),否则崩溃 - 混合键(如
[0 => 'x', 'id' => 123]):array_merge()仍可工作;[...$arr]会报错
array_merge() 的数字键重索引行为容易被忽略
这是线上 bug 高发区:array_merge() 对所有数字键强制重排,从 0 开始连续编号。哪怕你传入的是 [10 => 'a', 20 => 'b'] 和 [5 => 'c'],结果也是 [0 => 'a', 1 => 'b', 2 => 'c']。
如果你依赖原始键做后续处理(比如批量更新 SQL 中的 WHERE id IN (10,20)),用 array_merge() 会悄悄把键名“洗掉”,导致逻辑断裂。
立即学习“PHP免费学习笔记(深入)”;
- 要保留键名 → 改用
+运算符(但注意它不合并同名键,只保留左边) - 要合并且保留数字键 → 没有内置函数,得手写循环或用
array_replace_recursive()(效果不同,需验证) - 确认是否真需要合并 → 有时只是拼接,
array_values(array_merge(...))反而多此一举
性能差异在高频调用场景才明显
[...$arr] 是语法结构,编译期展开;array_merge() 是函数调用,有栈开销。单次调用几乎感知不到差别,但在循环内每秒执行上千次时,[...$arr] 稳定快 15–25%(PHP 8.2+ 实测)。
但这个优势有个前提:你传进去的变量必须是数组。如果写了 [...$maybeNull],PHP 7.4+ 会抛 TypeError;而 array_merge((array)$maybeNull, $arr) 能兜底转为空数组——这种容错性在不确定输入来源时很关键。
- 确定是数组 + 索引结构 + 高频调用 → 优先
[...$arr] - 输入可能为
null/false/字符串 → 必须先 cast:[...(array)$maybeNull],否则崩 - 需要兼容 PHP array_merge()(7.4 才支持数组中使用
...)
函数参数传递场景下,... 不只是语法糖
当你要把数组元素作为独立参数传给函数时,func(...$args) 和 call_user_func_array('func', $args) 效果一样,但前者是语言级支持,后者是反射调用,性能差一截,且无法被 OPcache 充分优化。
更重要的是:只有 ... 能正确传递引用参数(func(&$arg)),而 call_user_func_array() 会丢失引用语义,导致修改不生效。
- 调用自定义函数或内置函数(如
min(...$numbers))→ 无条件选... - 需要动态函数名(如
$fn(...$args))→ PHP 8.1+ 支持,旧版仍需call_user_func_array() - 参数含对象或资源 → 两者都支持,但
...语义更清晰,调试时堆栈也干净
真正卡住人的从来不是“哪个更快”,而是“哪个在当前数据结构下不报错”。先用 is_array() 和 array_keys() 快速探查键类型,再决定用哪个——比背规则管用。



















