... 展开运算符在 PHP 8+ 中性能略优但差异微小,核心区别在于类型安全与数字键处理:... 要求数组且保留原键,array_merge 允许非数组输入但会重排数字键并隐式转换,二者语义与适用场景根本不同。

array_merge 和 ... 在 PHP 8+ 中的性能差异真实存在吗?
在 PHP 8.0+ 环境下,... 展开运算符(splat)合并数组通常比 array_merge 快 10%–30%,但这个差距只在大量小数组或高频调用场景下才可测;日常业务中几乎感知不到。
关键不是“谁更快”,而是“谁更安全、更符合语义”。... 要求所有参数都是数组,而 array_merge 会把非数组参数转成 [0 => $value] —— 这个隐式转换常导致意外结果。
-
array_merge([1], "hello")返回[0 => 1, 0 => "h", 1 => "e", ...](字符串被拆成字符索引数组) -
[...[1], ..."hello"]直接抛出Fatal error: Uncaught TypeError: Cannot unpack string
什么时候必须用 array_merge?
当你要合并的变量可能为 null、false、字符串、对象,或者来自用户输入/数据库字段(类型不确定)时,array_merge 是唯一稳妥选择。
它对非数组参数的处理虽然诡异,但至少是可预测的(全部转为索引数组),而 ... 会直接中断执行。
立即学习“PHP免费学习笔记(深入)”;
- 合并配置项:
array_merge($default, $userConfig)——$userConfig可能是null或未定义 - 处理
$_GET或$_POST数据:array_merge($_GET, ['lang' => 'zh'])安全;用[...$_GET, 'lang' => 'zh']会报错,因为$_GET可能为空或非数组 - 需要保留数字键重排逻辑:只有
array_merge会重置数字键;...保持原键(包括字符串键和数字键)
... 的真实优势不在速度,而在表达意图
... 不是 array_merge 的替代品,而是“明确声明:此处必须是数组,且我要原样展开”的语法糖。它让代码自文档化更强,也更容易被静态分析工具(如 PHPStan)识别问题。
如果你已经 100% 确保所有操作数是数组(比如函数内部已做过 is_array() 检查,或来自类型声明的参数),那么用 ... 更清晰、更轻量。
- 函数参数解构:
function foo(array $a, array $b) { return [...$a, ...$b]; }—— 类型安全,语义直白 - 避免嵌套调用:
array_merge(...$arrays)需要先确保$arrays是二维数组;而[...$arrays]本身就会报错如果$arrays不是数组,反而更早暴露问题 - PHP 8.1+ 支持
...用于命名参数,但仅限于数组字面量或变量,不支持任意表达式
别忽略 key 冲突时的行为差异
两者对字符串键的处理一致(后覆盖前),但对数字键的处理根本不同 —— 这是线上 bug 最常藏身之处。
array_merge(['a' => 1, 2 => 3], ['b' => 4, 2 => 5]) → ['a' => 1, 'b' => 4, 0 => 3, 1 => 5](数字键被重排)
[...'a' => 1, 2 => 3, ...'b' => 4, 2 => 5] → ['a' => 1, 2 => 3, 'b' => 4, 2 => 5](数字键 2 被覆盖,不重排)
- 若你依赖数字键顺序(比如分页 offset/limit 数组),
...行为更可预期 - 若你靠
array_merge的重排特性做“扁平化”(例如合并多个[1,2]得到[0=>1,1=>2,2=>1,3=>2]),换用...会出错 - 混合键数组(如
[0=>'x', 'id'=>123])用...合并时,数字键 0 会被保留,不会变成新索引
真正容易被忽略的不是性能,而是数字键是否重排 —— 这个差异在重构时最致命,尤其当旧代码靠 array_merge 的副作用实现逻辑。



















