PHP 提供多種陣列合併方式,各有不同的鍵名衝突處理策略、索引重組行為與適用場景。本文深度對比 array_merge、array_merge_recursive、array_combine、+ 運算子等核心合併機制。
array array_merge(array ...$arrays): array
<?php
$face = ['J', 'Q', 'K', 'A']; // 索引 0,1,2,3
$numbered = ['2','3','4','5','6','7','8','9']; // 索引 0-7
$cards = array_merge($face, $numbered);
print_r($cards);
/*
Array
(
[0] => J
[1] => Q
[2] => K
[3] => A
[4] => 2
[5] => 3
[6] => 4
[7] => 5
[8] => 6
[9] => 7
[10] => 8
[11] => 9
)
數字鍵重新索引,依序附加
*/
// 字串鍵衝突測試
$a = ['x' => 1, 'y' => 2];
$b = ['y' => 20, 'z' => 3];
print_r(array_merge($a, $b));
// ['x'=>1, 'y'=>20, 'z'=>3] 字串鍵 'y' 後者覆蓋
// 混合鍵
$a = ['a' => 1, 0 => 'first'];
$b = ['b' => 2, 0 => 'second'];
print_r(array_merge($a, $b));
// ['a'=>1, 0=>'first', 'b'=>2, 1=>'second']
// 字串鍵合併,數字鍵重新索引附加
?>
<?php
$face = ['J', 'Q', 'K', 'A'];
$numbered = range(2, 10);
$cards = array_merge($face, $numbered);
shuffle($cards); // 隨機打亂
print_r($cards);
// 每次輸出順序不同,模擬發牌
?>
array array_merge_recursive(array ...$arrays): array
當字串鍵名衝突時,**不覆蓋**,而是將兩個值合併為一個新陣列,以原鍵名為鍵。
<?php
$class1 = ['john' => 100, 'james' => 85];
$class2 = ['micky' => 78, 'john' => 45]; // 'john' 衝突
$scores = array_merge_recursive($class1, $class2);
print_r($scores);
/*
Array
(
[john] => Array
(
[0] => 100 // 來自 class1
[1] => 45 // 來自 class2
)
[james] => 85 // 無衝突保持標量
[micky] => 78
)
*/
// 多層遞歸合併
$config1 = ['db' => ['host' => 'localhost', 'port' => 3306]];
$config2 = ['db' => ['user' => 'root', 'pass' => 'secret'], 'cache' => true];
print_r(array_merge_recursive($config1, $config2));
/*
Array
(
[db] => Array
(
[host] => localhost
[port] => 3306
[user] => root
[pass] => secret
)
[cache] => true
)
注意:同名子陣列會遞歸合併,而非覆蓋
*/
?>
array array_combine(array $keys, array $values): array
$keys 的值將作為新陣列的鍵名,$values 作為對應值<?php
$abbreviations = ['AL', 'AK', 'AZ', 'AR'];
$states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas'];
$stateMap = array_combine($abbreviations, $states);
print_r($stateMap);
/*
Array
(
[AL] => Alabama
[AK] => Alaska
[AZ] => Arizona
[AR] => Arkansas
)
*/
// 實際應用:資料庫查詢結果轉字典
$rows = [
['id' => 1, 'name' => 'Alice', 'email' => 'alice@example.com'],
['id' => 2, 'name' => 'Bob', 'email' => 'bob@example.com']
];
// 以 id 為鍵建立查找表
$userMap = array_combine(
array_column($rows, 'id'),
$rows
);
// 結果: [1 => [...], 2 => [...]]
// CSV 欄位名與數據行組合
$headers = ['id', 'name', 'age'];
$row = [1, 'Alice', 25];
$record = array_combine($headers, $row);
// ['id'=>1, 'name'=>'Alice', 'age'=>25]
?>
<?php
function safeArrayCombine(array $keys, array $values): array {
if (count($keys) !== count($values)) {
throw new InvalidArgumentException(
"鍵陣列長度 (" . count($keys) . ") 與值陣列長度 (" . count($values) . ") 不匹配"
);
}
if (empty($keys)) {
return []; // PHP 8.0+ 允許,舊版本會報錯
}
return array_combine($keys, $values);
}
?>
$result = $a + $b;
<?php
$a = ['a' => 1, 'b' => 2, 0 => 'first'];
$b = ['b' => 20, 'c' => 3, 0 => 'second'];
echo "array_merge: ";
print_r(array_merge($a, b));
// ['a'=>1, 'b'=>20, 0=>'first', 1=>'second', 'c'=>3]
echo "+ 運算子: ";
print_r($a + $b);
// ['a'=>1, 'b'=>2, 0=>'first', 'c'=>3]
// 'b' 保留 $a 的 2,數字鍵 0 保留 $a 的 'first'
?>
<?php
$a = ['a' => 1, 'b' => 2];
$b = ['b' => 20, 'c' => 3];
// array_replace: 類似 array_merge 但不重新索引數字鍵
print_r(array_replace($a, $b));
// ['a'=>1, 'b'=>20, 'c'=>3] 數字鍵不重組
// 多陣列替換
$c = ['c' => 30];
print_r(array_replace($a, $b, $c));
// ['a'=>1, 'b'=>20, 'c'=>30] 後者覆蓋前者
?>
array_join() 是 implode() 的別名,**不是陣列合併函數**,而是陣列轉字串。注意區分。
| 操作 | 時間 (ms) | 記憶體增長 | 備註 |
|---|---|---|---|
| array_merge($a, $b) | ~15 | ~40MB | 創建新陣列,重新索引數字鍵 |
| $a + $b | ~8 | ~30MB | 較快,不重新索引 |
| array_merge_recursive | ~25 | ~50MB | 遞歸檢查較慢 |
| array_combine | ~10 | ~35MB | 需預先準備鍵值陣列 |
array_merge()array_merge_recursive()$defaults + $userConfigarray_combine()array_replace()+ 運算子或手動循環<?php
// 只合併非空值
function mergeNonEmpty(array ...$arrays): array {
$result = [];
foreach ($arrays as $arr) {
foreach ($arr as $k => $v) {
if ($v !== null && $v !== '') {
$result[$k] = $v;
}
}
}
return $result;
}
// 深度合併 (遞歸,但標量值覆蓋而非合併為陣列)
function deepMerge(array $a, array $b): array {
$result = $a;
foreach ($b as $k => $v) {
if (isset($result[$k]) && is_array($result[$k]) && is_array($v)) {
$result[$k] = deepMerge($result[$k], $v);
} else {
$result[$k] = $v; // 覆蓋
}
}
return $result;
}
// 使用
$default = ['db' => ['host' => 'localhost', 'port' => 3306], 'debug' => false];
$user = ['db' => ['user' => 'root'], 'debug' => true];
$config = deepMerge($default, $user);
/*
['db' => ['host'=>'localhost', 'port'=>3306, 'user'=>'root'], 'debug'=>true]
*/
?>
理解各種合併機制的語義差異,能避免「配置被意外覆蓋」、「數字索引亂序」、「衝突值丟失」等常見 Bug。根據業務語義選擇正確的合併策略,是陣列操作進階的關鍵。