array_multisort 接受可變參數,每個陣列後可跟 0~2 個旗標(順序 + 型別),旗標僅影響前一個陣列。這設計極靈活但也易誤用。
<?php
$arr1 = [1, 9, 5];
$arr2 = [6, 2, 4];
$arr3 = [3, 7, 8];
// 錯誤:旗標位置錯誤
array_multisort($arr1, $arr2, SORT_DESC, $arr3); // SORT_DESC 套用到 $arr2
// 正確:每組陣列+旗標成對
array_multisort($arr1, SORT_ASC, $arr2, SORT_DESC, SORT_NUMERIC, $arr3, SORT_ASC);
// $arr1 升序,$arr2 數值降序,$arr3 升序
?>
<?php
$guys = [
['name' => 'jake', 'score' => 80, 'grade' => 'A'],
['name' => 'jin', 'score' => 70, 'grade' => 'A'],
['name' => 'john', 'score' => 80, 'grade' => 'A'],
['name' => 'ben', 'score' => 20, 'grade' => 'B'],
];
// 目標:score 降序,同分 name 升序
$scores = array_column($guys, 'score');
$names = array_column($guys, 'name');
array_multisort($scores, SORT_DESC, $names, SORT_ASC, $guys);
/* 結果:
jake (80), john (80), jin (70), ben (20)
jake 排在 john 前因 name 升序
*/
?>
<?php
class ArrayHelper
{
/**
* 單欄位排序
* @param array $array 二維陣列
* @param string $key 排序鍵名
* @param int $direction SORT_ASC/SORT_DESC
* @return array
*/
public static function sortByCol(array $array, string $key, int $direction = SORT_ASC): array
{
return self::sortByMultiCols($array, [$key => $direction]);
}
/**
* 多欄位排序(類 SQL ORDER BY col1 DESC, col2 ASC)
* @param array $rows 資料集
* @param array $specs ['col1'=>SORT_DESC, 'col2'=>SORT_ASC, ...]
* @return array
*/
public static function sortByMultiCols(array $rows, array $specs): array
{
if (empty($rows) || empty($specs)) return $rows;
$sortArrays = [];
$sortRules = [];
foreach ($specs as $field => $direction) {
// 建立欄位值陣列,保留原鍵關聯
$colValues = [];
foreach ($rows as $k => $row) {
$colValues[$k] = $row[$field] ?? null;
}
$sortArrays[$field] = $colValues;
$sortRules[] = '$sortArrays[\'' . $field . '\']';
$sortRules[] = $direction;
}
// 組裝參數:欄位1值, 旗標1, 欄位2值, 旗標2, ..., &$rows
$args = [];
foreach ($sortRules as $rule) $args[] = $rule;
$args[] = '&$rows';
// 使用 call_user_func_array 避免 eval
// array_multisort 接受陣列解包 (PHP 5.6+)
array_multisort(...array_merge(
array_map(function($f) use ($sortArrays) { return $sortArrays[$f]; }, array_keys($specs)),
array_values($specs),
[&$rows]
));
return $rows;
}
}
// 使用範例
$rows = [
['id'=>1, 'parent'=>1, 'name'=>'A'],
['id'=>2, 'parent'=>1, 'name'=>'B'],
['id'=>3, 'parent'=>2, 'name'=>'C'],
['id'=>4, 'parent'=>2, 'name'=>'D'],
];
// parent 升序,name 降序
$sorted = ArrayHelper::sortByMultiCols($rows, [
'parent' => SORT_ASC,
'name' => SORT_DESC,
]);
?>
原文使用 eval() 動態建構呼叫,**極不推薦**(安全風險、難除錯、OpCache 不優化)。現代 PHP 使用 ... 解包配合 array_merge 或 call_user_func_array 即可安全動態呼叫。
array_column 會建立完整副本。可改用 array_keys + usort 閉包捕獲原陣列,避免額外記憶體。array_multisort 本身即就地修改,無額外回傳副本。array_multisort 的參數設計雖靈活,但易寫錯。封裝 sortByMultiCols 等工具函式,統一專案排序風格,並拋棄 eval 改用現代呼叫方式,能寫出更安全、可維護的排序代碼。複雜業務排序優先考慮資料庫 ORDER BY 下推。