前言:陣列排序是資料處理的核心技能
PHP 提供豐富的陣列排序函式,針對一維、多維、關聯式陣列都有對應方案。選對函式能讓程式碼更簡潔、效能更優異。本文系統整理所有排序函式差異、適用場景與實戰範例。
一維陣列排序函式完整對照
| 函式 | 排序依據 | 鍵名保留 | 順序 | 適用場景 |
sort() | 值 | ❌ 重設為 0..n | 升序 | 數值索引陣列,不在乎原鍵名 |
rsort() | 值 | ❌ 重設為 0..n | 降序 | 同上,需降序 |
asort() | 值 | ✅ 保留關聯 | 升序 | 關聯陣列依值排序 |
arsort() | 值 | ✅ 保留關聯 | 降序 | 同上,需降序 |
ksort() | 鍵名 | ✅ 保留關聯 | 升序 | 依鍵名字母/數字排序 |
krsort() | 鍵名 | ✅ 保留關聯 | 降序 | 同上,需降序 |
關鍵差異示範
<?php
$a = ["a" => 10, 0 => 5, "b" => 1];
sort($a); // [0=>1, 1=>5, 2=>10] 鍵名 'a','b' 消失
asort($a); // ["b"=>1, 0=>5, "a"=>10] 保留鍵名
ksort($a); // [0=>5, "a"=>10, "b"=>1] 依鍵名排序
?>
自訂比較函式排序
| 函式 | 比較對象 | 鍵名保留 |
uasort() | 值 | ✅ |
uksort() | 鍵名 | ✅ |
usort() | 值 | ❌ 重設索引 |
比較函式規範 (PHP 7+ 太空船運算子)
<?php
// 回傳負數:$a 排前面;0:不變;正數:$a 排後面
function cmp($a, $b) {
return $a <=> $b; // 升序
// return $b <=> $a; // 降序
}
// 多欄位排序
function cmpMulti($a, $b) {
// 先比 age 升序,再比 name 降序
return [$a['age'], -strcmp($a['name'], $b['name'])] <=> [$b['age'], -strcmp($b['name'], $a['name'])];
// 更簡潔寫法 (PHP 7+):
return [$a['age'], $b['name']] <=> [$b['age'], $a['name']]; // 注意:第二欄位若要降序需技巧處理
}
?>
實戰:選單依 order 欄位排序
<?php
$menu = [
'index' => ['name' => '首頁', 'order' => 3],
'intro' => ['name' => '企業概況', 'order' => 2],
'news' => ['name' => '新聞動態', 'order' => 1],
'product' => ['name' => '產品中心', 'order' => 4],
'contact' => ['name' => '聯絡我們', 'order' => 5],
];
uasort($menu, fn($a, $b) => $a['order'] <=> $b['order']);
// 結果順序:news(1) → intro(2) → index(3) → product(4) → contact(5)
?>
多維陣列排序:array_multisort 進階應用
array_multisort() 可同時排序多個陣列,或依多個欄位排序多維陣列,類似 SQL ORDER BY col1 DESC, col2 ASC。
基本機制:平行陣列同步排序
<?php
$a = [100, 80, 50, 10, 0];
$b = ["c", "f", "q", "e", "z"];
array_multisort($a, $b);
// $a: [0, 10, 50, 80, 100]
// $b: ["z", "e", "q", "f", "c"] // 原第5個 'z' 移到第1位
?>
多維陣列實戰:提取欄位陣列再排序
<?php
$records = [
["age" => 20, "name" => "li"],
["age" => 21, "name" => "ai"],
["age" => 20, "name" => "ci"],
["age" => 22, "name" => "di"],
];
// 步驟 1:提取排序欄位
$age = array_column($records, 'age');
$name = array_column($records, 'name');
// 步驟 2:排序 (最後一個參數是目標陣列)
array_multisort($age, SORT_NUMERIC, SORT_DESC,
$name, SORT_STRING, SORT_ASC,
$records);
/* 結果:
[0] => age:22, name:di
[1] => age:21, name:ai
[2] => age:20, name:ci (ci < li 字典序)
[3] => age:20, name:li
*/
?>
現代寫法:array_column 內聯 (PHP 5.5+)
<?php
array_multisort(
array_column($records, 'age'), SORT_DESC,
array_column($records, 'name'), SORT_ASC,
$records
);
?>
排序旗標完整說明
| 旗標 | 說明 |
SORT_ASC | 升序 (預設) |
SORT_DESC | 降序 |
SORT_REGULAR | 一般比較 (預設) |
SORT_NUMERIC | 數值比較 |
SORT_STRING | 字串比較 |
SORT_LOCALE_STRING | 依 locale 字串比較 (需 setlocale()) |
SORT_NATURAL | 自然排序 ("img2" < "img10") |
SORT_FLAG_CASE | 不區分大小寫 (配合 SORT_STRING) |
完整參數順序規則
array_multisort(
array1, [sort_flags1], [sort_order1],
array2, [sort_flags2], [sort_order2],
...,
target_array // 必須是最後一個參數
)
進階實戰案例
案例一:電商商品排序 (價格、銷量、評分、上架時間)
<?php
$products = [
['id'=>1, 'price'=>299, 'sales'=>150, 'rating'=>4.5, 'created'=>'2024-01-15'],
['id'=>2, 'price'=>199, 'sales'=>300, 'rating'=>4.2, 'created'=>'2024-02-10'],
['id'=>3, 'price'=>299, 'sales'=>150, 'rating'=>4.8, 'created'=>'2024-01-20'],
['id'=>4, 'price'=>399, 'sales'=>80, 'rating'=>4.9, 'created'=>'2024-03-01'],
];
// 預設排序:銷量降序 → 評分降序 → 價格升序 → 上架時間升序
array_multisort(
array_column($products, 'sales'), SORT_NUMERIC, SORT_DESC,
array_column($products, 'rating'), SORT_NUMERIC, SORT_DESC,
array_column($products, 'price'), SORT_NUMERIC, SORT_ASC,
array_column($products, 'created'),SORT_STRING, SORT_ASC,
$products
);
?>
案例二:中文姓名筆畫/拼音排序
<?php
$names = ['張三', '李四', '王五', '趙六', '陳七'];
// 使用 Collator (intl 擴充套件) 正確中文排序
$collator = new Collator('zh_TW');
$collator->setStrength(Collator::TERTIARY); // 區分聲調
usort($names, [$collator, 'compare']);
// 或自然排序旗標 (PHP 5.4+)
sort($names, SORT_NATURAL | SORT_FLAG_CASE);
?>
效能考量與替代方案
| 場景 | 推薦方案 | 理由 |
| 資料庫查詢結果 | SQL ORDER BY | 索引優化、避免記憶體排序 |
| 小型陣列 (< 10k) | PHP 內建排序 | 簡單直接、效能足夠 |
| 大型陣列 (> 100k) | 分批處理/資料庫排序 | 記憶體與 CPU 考量 |
| 複雜物件排序 | usort + 太空船運算子 | 邏輯封裝在比較函式 |
| 需穩定排序 | PHP 8.0+ 內建穩定 | 相同值保持原相對順序 |
PHP 8.0+ 穩定排序保證
PHP 8.0 起所有排序函式保證 穩定排序:相同比較值的元素,相對順序不變。舊版本 sort()/usort() 為不穩定排序。
常見陷阱避坑指南
| 陷阱 | 現象 | 解決 |
| sort() 導致關聯鍵遺失 | 字串鍵名消失 | 改用 asort()/ksort() |
| array_multisort 陣列長度不一 | Warning: Array sizes are inconsistent | 確保所有排序陣列長度相同 |
| 旗標順序錯誤 | 排序結果不如預期 | 嚴格遵循:陣列、類型旗標、順序旗標 |
| 中文排序亂序 | 非預期順序 | 使用 Collator 或 SORT_LOCALE_STRING + setlocale() |
| 比較函式回傳非整數 | PHP 7+ TypeError | 使用 <=> 或確保回傳 -1/0/1 |
| float 精度導致排序異常 | 0.1+0.2 != 0.3 影響順序 | 乘以倍數轉整數比較或用 bcmath |
總結:選對工具的決策樹
需要排序?
├─ 一維陣列
│ ├─ 依值排序,不在乎鍵名 → sort() / rsort()
│ ├─ 依值排序,保留鍵名 → asort() / arsort()
│ ├─ 依鍵名排序 → ksort() / krsort()
│ └─ 自訂邏輯 → uasort() / uksort() / usort()
└─ 多維陣列 / 多欄位排序
├─ 簡單多欄位 → array_multisort() + array_column()
├─ 複雜物件/邏輯 → usort() + 太空船運算子
└─ 超大資料集 → 資料庫 ORDER BY / 外部排序
掌握這些排序工具與選擇邏輯,能讓資料處理程式碼更專業、更高效。