array_merge() 在處理數字索引陣列時,會**重新排序並從 0 開始連續索引**,而非覆蓋同鍵值。這行為常導致邏輯錯誤。
<?php
$a1 = [1 => 'abc', 3 => 10];
$a2 = [1 => 'efg', 3 => 20];
print_r(array_merge($a1, $a2));
/*
輸出:
Array
(
[0] => abc // 原鍵 1 變 0
[1] => 10 // 原鍵 3 變 1
[2] => efg // 原鍵 1 變 2
[3] => 20 // 原鍵 3 變 3
)
*/
官方文件說明:「若陣列包含數字鍵名,後方值不會覆蓋,而是附加在後並重新索引。」
| 需求 | 方案 | 範例 |
|---|---|---|
| 保留數字鍵名,後者覆蓋前者 | 使用 + 運算子 | $result = $a1 + $a2; → `[1=>'abc', 3=>10]` (左優先) |
| 保留數字鍵名,前者覆蓋後者 | $result = $a2 + $a1; | → `[1=>'efg', 3=>20]` |
| 字串鍵名正常合併 (後覆蓋前) | array_merge 行為正確 | ['a'=>1] + ['a'=>2] → `['a'=>1]` (左優先)array_merge(['a'=>1], ['a'=>2]) → `['a'=>2]` |
| 需遞迴合併多維陣列 | 自寫遞迴函式或用 array_merge_recursive (注意數值會被包成陣列) | 見下方 |
function arrayMergeRecursiveDistinct(array &$a1, array $a2): array {
foreach ($a2 as $k => $v) {
if (is_array($v) && isset($a1[$k]) && is_array($a1[$k])) {
$a1[$k] = arrayMergeRecursiveDistinct($a1[$k], $v);
} else {
$a1[$k] = $v;
}
}
return $a1;
}
array_merge,合併數字鍵/混合鍵且需保留鍵名用 +。array_merge((array)$a1, (array)$a2) 仍會重新索引數字鍵,建議顯式處理。