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

PHP 實現無限級分類:遞歸與引用構建樹形結構

     編輯:PHP 相關知識

PHP 實現無限級分類:遞歸與引用構建樹形結構

無限級分類(多級分類)是電商、CMS、權限系統的基礎數據結構。核心思想:每條記錄擁有 id 與 pid(父級 ID),根節點 pid=0。本文提供兩種經典 PHP 實現:遞歸查詢輸出扁平列表(適合前端遞歸渲染)與 引用構建多維樹形數組(適合 API 直接輸出 JSON)。

方案一:遞歸生成帶縮進的扁平列表(ThinkPHP 風格)

public function getlist($pid = 0, &$result = [], $spac = 0) {
    $spac += 2;
    $list = M('liuyan')->where('pid=' . $pid)->select();
    foreach ($list as $val) {
        $val['content'] = str_repeat(' ', $spac) . $val['content']; // 視覺縮進
        $result[] = $val;
        $this->getlist($val['id'], $result, $spac); // 遞歸子節點
    }
    return $result;
}
  • 優點:代碼極簡,內存佔用小,適合後台樹形表格展示。
  • 缺點:每層遞歸都要查詢數據庫(N+1 問題),大數據量時性能差。

方案二:單次查詢 + 引用構建多維樹(通用高性能)

function genTree($items, $id = 'id', $pid = 'pid', $son = 'children') {
    $tree = [];       // 格式化後的樹
    $tmpMap = [];     // 臨時扁平映射:id => 節點引用

    // 1. 建立 id 映射
    foreach ($items as $item) {
        $tmpMap[$item[$id]] = $item;
    }

    // 2. 遍歷構建父子關係(利用引用 &)
    foreach ($items as $item) {
        if (isset($tmpMap[$item[$pid]])) {
            // 父節點存在,將當前節點引用掛載到父節點的 children 數組
            $tmpMap[$item[$pid]][$son][] = &$tmpMap[$item[$id]];
        } else {
            // 無父節點(pid=0 或父節點不在數據集),作為根節點
            $tree[] = &$tmpMap[$item[$id]];
        }
    }
    unset($tmpMap); // 釋放映射表
    return $tree;
}

測試數據與輸出示例

$items1 = [
    ['id'=>1,  'pid'=>0,  'name'=>'一級11'],
    ['id'=>11, 'pid'=>0,  'name'=>'一級12'],
    ['id'=>2,  'pid'=>1,  'name'=>'二級21'],
    ['id'=>10, 'pid'=>11, 'name'=>'二級22'],
    ['id'=>3,  'pid'=>1,  'name'=>'二級23'],
    // ... 更多層級
];
var_dump(genTree($items1));

輸出將呈現巢狀結構:

array(
  0 => array('id'=>1, 'pid'=>0, 'name'=>'一級11', 'children'=>array(
        0 => array('id'=>2, 'pid'=>1, 'name'=>'二級21', 'children'=>array(...)),
        1 => array('id'=>3, 'pid'=>1, 'name'=>'二級23'),
        ...
    )),
  1 => array('id'=>11, 'pid'=>0, 'name'=>'一級12', 'children'=>array(...))
)

性能與選型建議

維度遞歸查庫 (方案一)單查+引用構樹 (方案二)
查詢次數O(節點數)1 次
時間複雜度O(N log N) ~ O(N²)O(N)
內存佔用低(流式處理)中(需載入全量數據)
適用場景數據量小、實時性要求高、後台管理數據量大、API 輸出、前端樹形組件

進階優化方向

  • 閉包表 / 路徑枚舉:在表中冗存 path (如 0,1,2,5) 或 depth,支持單條 SQL 查詢子樹、祖先鏈。
  • 緩存樹結構:Redis 存儲 JSON 樹,數據變更時增量更新或重建。
  • 非遞歸遍歷:用棧/隊列實現 BFS/DFS,避免遞歸棧溢出(PHP 默認棧深度有限)。

掌握「單次查詢 + 引用構建樹」模式,是 PHP 處理層級數據的必備技能,亦是許多框架(Laravel nestedset、ThinkPHP Tree)底層實現的核心邏輯。

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