從數據庫查詢或 API 獲取的列表數據通常為多維數組,需按某字段 (如 price, created_at, sort_order) 升序/降序排列。PHP 內置 array_multisort 功能強大但調用繁瑣,本文封裝一個通用單行調用函數。
<?php
/**
* 多維數組按字段排序 (原地修改)
* @param array $array 待排序數組 (引用)
* @param string $field 排序字段名
* @param bool $desc true=降序, false=升序 (默認)
*/
function sortArrByField(array &$array, string $field, bool $desc = false): void {
if (empty($array)) return;
$fieldArr = array_column($array, $field); // PHP 5.5+ 專用,比 foreach 快
$sortFlag = $desc ? SORT_DESC : SORT_ASC;
array_multisort($fieldArr, $sortFlag, $array);
}
?>
<?php
$products = [
['id'=>1, 'name'=>'A', 'price'=> 299, 'sales'=> 100],
['id'=>2, 'name'=>'B', 'price'=> 199, 'sales'=> 500],
['id'=>3, 'name'=>'C', 'price'=> 399, 'sales'=> 50],
];
// 價格升序
sortArrByField($products, 'price');
/* 結果: B(199), A(299), C(399) */
// 銷量降序
sortArrByField($products, 'sales', true);
/* 結果: B(500), A(100), C(50) */
// 多字段排序:先按銷量降序,銷量相同再按價格升序
$field1 = array_column($products, 'sales');
$field2 = array_column($products, 'price');
array_multisort($field1, SORT_DESC, $field2, SORT_ASC, $products);
?>
<?php
/**
* 增強版:支持多字段、自定義排序標誌、自然排序、保持鍵名
*/
function multisort(array &$array, array $specs, int $flags = SORT_REGULAR): void {
if (empty($array)) return;
$args = [];
foreach ($specs as $spec) {
// $spec = ['field'=>'price', 'order'=>SORT_DESC, 'flags'=>SORT_NUMERIC]
$field = $spec['field'];
$order = $spec['order'] ?? SORT_ASC;
$flag = $spec['flags'] ?? $flags;
$args[] = array_column($array, $field);
$args[] = $order;
$args[] = $flag;
}
$args[] = &$array; // 最後傳入原數組引用
array_multisort(...$args);
}
// 使用
multisort($products, [
['field'=>'sales', 'order'=>SORT_DESC, 'flags'=>SORT_NUMERIC],
['field'=>'price', 'order'=>SORT_ASC, 'flags'=>SORT_NUMERIC],
]);
?>
| 問題 | 原因 | 解決 |
|---|---|---|
| 排序後數字鍵名重置為 0,1,2... | array_multisort 默認重置數字索引 | 傳入關聯數組 (字符串鍵) 或排序前保存鍵名後恢復 |
| 字符串數字 "100" < "20" (字典序) | 默認 SORT_STRING | 指定 SORT_NUMERIC 標誌 |
| 字段值包含 null/不存在 | array_column 返回 null,排序靠前 | 預處理填充默認值,或過濾後再合併 |
| 大數組性能差 | array_column + array_multisort 需複製內存 | 數據量 > 10萬 建議在 SQL ORDER BY 或 Redis ZSET 排序 |
// Laravel Collection
$products->sortBy('price')->values()->all(); // 升序
$products->sortByDesc('sales')->values()->all(); // 降序
$products->sortBy([['sales','desc'], ['price','asc']]); // 多字段
// Symfony
use Symfony\Component\PropertyAccess\PropertyAccessor;
// 或使用 usort + 閉包比較器
sortArrByField 以 3 行核心代碼解決 90% 單字段排序需求,配合 array_column (PHP 5.5+) 代碼極其簡潔高效。複雜多字段排序直接調用 array_multisort 或使用框架 Collection 方法。