首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 陣列合併操作深度解析:array_merge、array_merge_recursive、array_combine 與運算子比較

     編輯:PHP 相關知識

PHP 陣列合併操作深度解析

PHP 提供多種陣列合併方式,各有不同的鍵名衝突處理策略、索引重組行為與適用場景。本文深度對比 array_merge、array_merge_recursive、array_combine、+ 運算子等核心合併機制。

一、array_merge() - 標準合併

array array_merge(array ...$arrays): array

核心規則

  1. 字串鍵名衝突:後面的陣列值覆蓋前面的
  2. 數字鍵名:重新從 0 開始連續索引,不覆蓋,依序附加
  3. 單一數字索引陣列:會重新索引
  4. 不修改原陣列:返回新陣列

範例演示

<?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_merge_recursive() - 遞歸合併

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_combine() - 鍵值對組合

array array_combine(array $keys, array $values): array

嚴格要求

  1. 兩個陣列**長度必須相同**
  2. 兩個陣列**不能為空** (PHP 8.0+ 允許空陣列返回空陣列)
  3. $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;

核心規則

  • 鍵名不衝突:合併所有鍵值對
  • 鍵名衝突:保留左側 ($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'
?>

適用場景

  • 預設配置 + 用戶配置 (用戶配置只補充不覆蓋預設)
  • 陣列去重保留首次出現順序
  • 快速合併不想被覆蓋的鍵

五、其他合併相關函數

array_replace() / array_replace_recursive()

<?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() 別名

array_join() 是 implode() 的別名,**不是陣列合併函數**,而是陣列轉字串。注意區分。

六、效能比較 (百萬級元素測試參考)

操作時間 (ms)記憶體增長備註
array_merge($a, $b)~15~40MB創建新陣列,重新索引數字鍵
$a + $b~8~30MB較快,不重新索引
array_merge_recursive~25~50MB遞歸檢查較慢
array_combine~10~35MB需預先準備鍵值陣列

七、最佳實踐選擇指南

  1. 一般合併、數字索引重組 → array_merge()
  2. 配置分層、需保留衝突值 → array_merge_recursive()
  3. 預設值填充、不想覆蓋現有鍵 → $defaults + $userConfig
  4. 兩陣列一一對應組合成鍵值對 → array_combine()
  5. 替換特定鍵值、保持數字索引 → array_replace()
  6. 大量數據高效能合併 → 考慮 + 運算子或手動循環

八、進階技巧:條件式合併

<?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。根據業務語義選擇正確的合併策略,是陣列操作進階的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved