首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP array_multisort 進階用法:參數靈活性、多維陣列排序封裝與 QeePHP 實戰模式

     編輯:PHP 綜合知識

參數靈活性深度解析

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 升序
*/
?>

通用封裝:sortByCol / sortByMultiCols(參考 QeePHP)

<?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 版本風險與現代替代

原文使用 eval() 動態建構呼叫,**極不推薦**(安全風險、難除錯、OpCache 不優化)。現代 PHP 使用 ... 解包配合 array_merge 或 call_user_func_array 即可安全動態呼叫。

記憶體優化技巧

  • 大資料集: array_column 會建立完整副本。可改用 array_keys + usort 閉包捕獲原陣列,避免額外記憶體。
  • 就地排序: array_multisort 本身即就地修改,無額外回傳副本。

結語

array_multisort 的參數設計雖靈活,但易寫錯。封裝 sortByMultiCols 等工具函式,統一專案排序風格,並拋棄 eval 改用現代呼叫方式,能寫出更安全、可維護的排序代碼。複雜業務排序優先考慮資料庫 ORDER BY 下推。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved