「二維陣列按某列排序」是 PHP 開發高頻需求(如:商品按價格、用戶按註冊時間、文章按瀏覽量)。PHP 核心函數 array_multisort() 是實現此功能的**標準、最高效**工具。本文將深度解析其「多陣列同步排序」核心機制,提供開箱即用的通用封裝函數,並對比 usort 等替代方案,助你寫出高性能、可維護的排序代碼。
array_multisort() 可接收**多個陣列**作為參數,後面可跟排序標誌(SORT_ASC/SORT_DESC、SORT_REGULAR/SORT_NUMERIC/SORT_STRING),**最後一個參數必須是要排序的目標陣列(通常是原二維陣列)**。
執行邏輯:
這類似 SQL 的 ORDER BY col1 DESC, col2 ASC,每個依據陣列就是一個 ORDER BY 項。
<?php
$data = [
['volume' => 67, 'edition' => 2],
['volume' => 86, 'edition' => 1],
['volume' => 85, 'edition' => 6],
['volume' => 98, 'edition' => 2],
['volume' => 86, 'edition' => 6],
['volume' => 67, 'edition' => 7],
];
// 1. 提取排序依據列(建立並行陣列)
foreach ($data as $key => $row) {
$volume[$key] = $row['volume']; // 第 1 依據:volume
$edition[$key] = $row['edition']; // 第 2 依據:edition
}
// 2. 多重排序:volume 降序,edition 升序,最終同步排序 $data
// 參數順序:依據1陣列, 依據1標誌, 依據2陣列, 依據2標誌, ..., 目標陣列
array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data);
/* 結果:
Array (
[0] => Array ( [volume] => 98 [edition] => 2 )
[1] => Array ( [volume] => 86 [edition] => 1 ) // volume 同 86,edition 1 < 6
[2] => Array ( [volume] => 86 [edition] => 6 )
[3] => Array ( [volume] => 85 [edition] => 6 )
[4] => Array ( [volume] => 67 [edition] => 2 ) // volume 同 67,edition 2 < 7
[5] => Array ( [volume] => 67 [edition] => 7 )
)
*/
?>
<?php
/**
* 二維陣列多列排序(支援單列/多列、升序/降序、數值/字符串比較)
*
* @param array $data 待排序二維陣列(引用,將被修改)
* @param array $columns 排序規則陣列,格式:
* [
* ['column' => 'price', 'order' => SORT_DESC, 'type' => SORT_NUMERIC],
* ['column' => 'name', 'order' => SORT_ASC, 'type' => SORT_STRING],
* ]
* 簡寫:['price' => SORT_DESC, 'name' => SORT_ASC] (類型自動判斷)
* @param bool $preserveKeys 是否保留原鍵名(默認 false,重建 0..N 索引)
* @return array 排序後的陣列(同 $data 引用)
*/
function array_multisort_columns(array &$data, array $columns, bool $preserveKeys = false): array {
if (empty($data) || empty($columns)) return $data;
// 標準化規則
$sortArgs = [];
foreach ($columns as $col => $rule) {
if (is_int($col)) { // 簡寫格式:['price', 'name'] 或 ['price' => SORT_DESC]
$col = $rule;
$rule = [];
}
$order = $rule['order'] ?? SORT_DESC;
$type = $rule['type'] ?? SORT_REGULAR;
// 提取列值陣列
$colValues = array_column($data, $col);
if (empty($colValues)) {
trigger_error("排序列 '$col' 不存在於數據中", E_USER_WARNING);
continue;
}
// 自動判斷類型(若未指定)
if ($type === SORT_REGULAR) {
$firstVal = reset($colValues);
$type = is_numeric($firstVal) ? SORT_NUMERIC : SORT_STRING;
}
$sortArgs[] = $colValues;
$sortArgs[] = $order;
$sortArgs[] = $type;
}
// 最後加入目標陣列(引用)
$sortArgs[] = &$data;
// 執行排序
array_multisort(...$sortArgs);
// 可選:重建索引
if (!$preserveKeys) {
$data = array_values($data);
}
return $data;
}
// === 使用示例 ===
$products = [
['id' => 1, 'name' => '手機', 'price' => 5999, 'stock' => 100, 'category' => '電子'],
['id' => 2, 'name' => '筆記本', 'price' => 8999, 'stock' => 50, 'category' => '電子'],
['id' => 3, 'name' => '書包', 'price' => 199, 'stock' => 200, 'category' => '箱包'],
['id' => 4, 'name' => '滑鼠', 'price' => 99, 'stock' => 500, 'category' => '電子'],
['id' => 5, 'name' => '鍵盤', 'price' => 299, 'stock' => 300, 'category' => '電子'],
];
// 1. 單列排序:價格降序
array_multisort_columns($products, ['price' => SORT_DESC]);
// 結果:筆記本(8999) -> 手機(5999) -> 鍵盤(299) -> 書包(199) -> 滑鼠(99)
// 2. 多列排序:類別升序,價格降序
array_multisort_columns($products, [
['column' => 'category', 'order' => SORT_ASC, 'type' => SORT_STRING],
['column' => 'price', 'order' => SORT_DESC, 'type' => SORT_NUMERIC],
]);
/* 結果:
箱包類:書包(199)
電子類:筆記本(8999) -> 手機(5999) -> 鍵盤(299) -> 滑鼠(99)
*/
// 3. 簡寫格式:庫存升序
array_multisort_columns($products, ['stock' => SORT_ASC]);
?>
| 方案 | 時間複雜度 | 實際速度 (10萬行) | 代碼複雜度 | 適用場景 |
|---|---|---|---|---|
| array_multisort | O(N log N) * 列數 | **最快 (C 底層實現)** | 低(提取列 + 一行調用) | **常規多列排序首選** |
| usort + 回調 | O(N log N) * 比較次數 | 慢 10-50 倍 (PHP 回調開銷大) | 中(需寫比較函數) | 極複雜邏輯(如多字段混合、非標準比較) |
| 自定義快排/堆排 | O(N log N) | 極慢 (純 PHP 實現) | 高 | 教學/特殊算法研究 |
結論: **只要排序邏輯可用「多列值比較」表達,array_multisort 絕對是性能王者。** 僅在邏輯極其複雜(如:按某列取模後排序、需訪問外部服務比較)時才考慮 usort。
array_multisort **會重建數字索引 (0,1,2...)**,原關聯鍵名丟失。若需保留,排序後用 array_combine 恢復,或使用封裝函數的 $preserveKeys=true(內部實現需額外邏輯)。array_column 遇到不存在的列返回空陣列,導致排序無效或報警。**必須預檢或捕獲警告。**SORT_REGULAR 比較異常。**顯式指定 SORT_NUMERIC 或 SORT_STRING,或預處理統一類型。**&$data),直接傳表達式會報錯。usort(雖慢但省內存)。PHP 二維陣列排序,**array_multisort 是核心、標準、高性能方案**。掌握其「提取依據列陣列 → 同步多陣列排序」機制,配合通用封裝函數 array_multisort_columns(),即可優雅解決 99% 的業務排序需求:單列/多列、升序/降序、數值/字符串、保留鍵名/重建索引。切記:性能敏感場景堅決避免 usort 回調,善用 C 底層優勢,讓排序在毫秒級完成。