PHP 數組合併看似簡單,實則暗藏「鍵名重建」與「值覆蓋」的雙重陷阱。本文通過 6 組對比實驗,徹底釐清 array_merge() 與 + 運算符在數值鍵、字符串鍵、混合鍵下的行為差異,並提供一行代碼實現「數值鍵數組合併去重」的最佳實踐。
| 場景 | array_merge() | + 運算符 |
|---|---|---|
| 數值鍵相同 | 不覆蓋,重新索引追加 (0,1,2,3...) | 保留首次出現,拋棄後續 |
| 字符串鍵相同 | 後覆蓋前 | 保留首次出現,拋棄後續 |
| 鍵名類型不同 (0 vs '0') | 視為不同鍵,均保留並重新索引 | PHP 視為同鍵,保留首次 |
$a = ['a', 'b']; // [0=>a, 1=>b]
$b = ['c', 'd']; // [0=>c, 1=>d]
var_dump($a + $b); // [0=>a, 1=>b] ← 保留首個
var_dump(array_merge($a, $b)); // [0=>a, 1=>b, 2=>c, 3=>d] ← 重新索引追加
$a = [0=>'a', 1=>'b'];
$b = [0=>'c', 1=>'b']; // 鍵 0,1 重複
$a + $b; // [0=>a, 1=>b]
array_merge($a, $b); // [0=>a, 1=>b, 2=>c, 3=>b] ← 鍵 1 的值 'b' 被保留兩次!
$a = ['a', 'b']; // [0=>a, 1=>b]
$b = ['0'=>'c', 1=>'b']; // 字符串 '0' 和數值 1
$a + $b; // [0=>a, 1=>b] ← '0' 被視為 0,拋棄 'c'
array_merge($a, $b); // [0=>a, 1=>b, 2=>c, 3=>b] ← 視為不同鍵,重新索引
$a = [0=>'a', 1=>'b'];
$b = ['0'=>'c', '1'=>'b'];
$a + $b; // [0=>a, 1=>b]
array_merge($a, $b); // [0=>a, 1=>b, 2=>c, 3=>b]
需求:合併兩個數值索引數組,去除重複值,保留首次出現順序,重新建立連續索引。
function mergeNumericArraysUnique(array $arr1, array $arr2): array {
return array_keys(array_flip($arr1) + array_flip($arr2));
}
// 測試
$arr1 = ['aa', 'bb', 'cc'];
$arr2 = ['aa2', 'bb', 'cc2'];
print_r(mergeNumericArraysUnique($arr1, $arr2));
/*
Array
(
[0] => aa
[1] => bb
[2] => cc
[3] => aa2
[4] => cc2
)
*/
array_flip($arr1):值變鍵,鍵變值 → ['aa'=>0, 'bb'=>1, 'cc'=>2],自動去重(後值覆蓋前鍵,但我們只關心鍵名)+ 運算符合併:保留首次出現的鍵,即 $arr1 中值優先array_keys():提取鍵名 → 即原數組值,並自動生成連續數值索引array_keys(array_flip($arr2) + array_flip($arr1)); // 交換順序
array_flip(array_flip($arr1) + array_flip($arr2)); // 不用 array_keys
function mergeMultipleUnique(array ...$arrays): array {
$flipped = [];
foreach ($arrays as $arr) {
$flipped += array_flip($arr); // 依次合併,首個優先
}
return array_keys($flipped);
}
// 基準測試:10,000 元素數組,50% 重複
$arr1 = range(1, 10000);
$arr2 = range(5000, 15000);
// 方法 1:flip + 鍵 (本文推薦)
$start = microtime(true);
$result1 = array_keys(array_flip($arr1) + array_flip($arr2));
echo "flip+keys: " . (microtime(true) - $start) * 1000 . " ms\n"; // ~2.1 ms
// 方法 2:array_unique + array_merge
$start = microtime(true);
$result2 = array_unique(array_merge($arr1, $arr2));
echo "unique+merge: " . (microtime(true) - $start) * 1000 . " ms\n"; // ~3.8 ms
// 方法 3:迴圈 in_array 檢查
$start = microtime(true);
$result3 = $arr1;
foreach ($arr2 as $v) {
if (!in_array($v, $result3)) $result3[] = $v;
}
echo "loop+in_array: " . (microtime(true) - $start) * 1000 . " ms\n"; // ~180 ms (O(n²) 災難)
array_merge():語義明確「合併」,配合 array_values() 重建索引最安全+:但記住它不重建索引,後續常需 array_values()array_keys(array_flip($a) + array_flip($b)) 兼具性能與語義in_array:大數據量下性能指數級下降array_merge 視為不同,+ 視為相同,極易導致邏輯 BugPHP 數組合併的核心複雜度在於「鍵名類型轉換規則」與「重複值處理策略」的耦合。掌握 array_flip + + 運算符的組合拳,能以 O(n) 時間複雜度優雅解決 90% 的數值鍵數組去重合併需求,是每個 PHP 開發者必備的工具箱技能。