二維數組排序是業務開發高頻需求。本文對比 array_multisort 與 usort 兩大主流方案,分析適用場景、性能差異、代碼複雜度,提供選型指南。
$users = [
['name' => 'Tom', 'age' => 20, 'score' => 85],
['name' => 'Ann', 'age' => 18, 'score' => 92],
['name' => 'Jack', 'age' => 22, 'score' => 85],
['name' => 'Lucy', 'age' => 18, 'score' => 78],
];
需求:年齡升序,年齡相同則分數降序。
// 1. 提取排序列
$ages = array_column($users, 'age');
$scores = array_column($users, 'score');
// 2. 多鍵排序 (引用傳遞,修改原數組)
array_multisort($ages, SORT_ASC, $scores, SORT_DESC, $users);
/* 結果:
[
['name'=>'Ann', 'age'=>18, 'score'=>92], // 年齡最小,分數最高
['name'=>'Lucy', 'age'=>18, 'score'=>78], // 年齡相同,分數較低
['name'=>'Tom', 'age'=>20, 'score'=>85],
['name'=>'Jack', 'age'=>22, 'score'=>85],
]
*/
SORT_NUMERIC/SORT_STRING/SORT_NATURAL 等標誌usort($users, function($a, $b) {
// 年齡升序
if ($a['age'] != $b['age']) {
return $a['age'] <=> $b['age'];
}
// 年齡相同,分數降序
return $b['score'] <=> $a['score'];
});
/* 同樣結果,邏輯完全可控 */
<?php
$data = [];
for ($i = 0; $i < 50000; $i++) {
$data[] = ['age' => rand(18, 60), 'score' => rand(0, 100)];
}
$copy1 = $data;
$copy2 = $data;
// array_multisort
$start = microtime(true);
$ages = array_column($copy1, 'age');
$scores = array_column($copy1, 'score');
array_multisort($ages, SORT_ASC, $scores, SORT_DESC, $copy1);
echo "array_multisort: " . (microtime(true) - $start) . "s\n";
// usort
$start = microtime(true);
usort($copy2, function($a, $b) {
if ($a['age'] != $b['age']) return $a['age'] <=> $b['age'];
return $b['score'] <=> $a['score'];
});
echo "usort: " . (microtime(true) - $start) . "s\n";
/* 典型輸出:
array_multisort: 0.045s
usort: 0.082s (約 2x 慢)
*/
/**
* 通用多字段排序 (基於 usort,靈活優先)
* @param array &$data 數據引用
* @param array $fields ['field' => SORT_ASC|SORT_DESC, ...]
* @param callable|null $preprocess 值預處理 fn($item, $field)
*/
function multiSort(array &$data, array $fields, callable $preprocess = null) {
usort($data, function($a, $b) use ($fields, $preprocess) {
foreach ($fields as $field => $direction) {
$valA = $preprocess ? $preprocess($a, $field) : ($a[$field] ?? null);
$valB = $preprocess ? $preprocess($b, $field) : ($b[$field] ?? null);
if ($valA == $valB) continue;
$cmp = $valA <=> $valB;
return $direction === SORT_DESC ? -$cmp : $cmp;
}
return 0;
});
}
// 使用示例
multiSort($users, [
'age' => SORT_ASC,
'score' => SORT_DESC,
]);
// 複雜場景:按名稱長度降序
multiSort($users, [
'name' => SORT_DESC,
], fn($item, $field) => strlen($item[$field]));
array_multisort 簡潔優雅usort 靈活可控array_multisort 專為此設計usort + 箭頭函數,代碼可讀性最高array_multisortSplHeap/SplPriorityQueue 實現增量排序/Top-K理解兩者機制差異,根據業務場景靈活選擇,才能寫出高性能、可維護的排序代碼。