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

ThinkPHP 兩層分類遞迴讀取:父子關聯資料一次查詢輸出

     編輯:PHP 綜合知識

前言

電商、CMS 專案常需呈現「二級分類」結構:一級分類下包含多個子分類。ThinkPHP 的 ORM 配合巢狀迴圈可輕鬆完成。本文示範以單一查詢取得所有一級分類,再逐筆查詢子分類並掛載至 child 鍵,最終輸出巢狀陣列供模板直接渲染。

實作程式碼

<?php
// 控制器動作
public function categoryList() {
    $Category = D('Category');

    // 1. 取得所有一級分類 (parent_id = 0)
    $parentList = $Category->where('category_pid = 0')->select();

    if (!empty($parentList)) {
        foreach ($parentList as $key => $val) {
            $pid = $val['category_id'];

            // 2. 查詢該父分類下的子分類
            $children = $Category->where("category_pid = $pid")->select();

            // 3. 掛載至 child 鍵
            $parentList[$key]['child'] = $children;

            // 除錯:列印最後執行的 SQL
            // echo $Category->getLastSql();
        }
    }

    // 4. 指派給模板
    $this->assign('Category', $parentList);
    $this->display();
}
?>

模板渲染範例

<!-- 模板檔案 -->
<ul class="category-tree">
    <volist name="Category" id="cat">
        <li>
            <a href="{:U('Article/index', ['cid' => $cat.category_id])}">
                {$cat.category_name}
            </a>
            <if condition="!empty($cat.child)">
                <ul class="sub-category">
                    <volist name="cat.child" id="sub">
                        <li>
                            <a href="{:U('Article/index', ['cid' => $sub.category_id])}">
                                {$sub.category_name}
                            </a>
                        </li>
                    </volist>
                </ul>
            </if>
        </li>
    </volist>
</ul>

效能優化建議

問題解決方案備註
N+1 查詢:1 筆父 + N 筆子 = N+1 次 SQL一次撈全部分類,PHP 端組裝樹狀結構適用分類總數 < 500 筆
分類超過千筆資料庫加 path 欄位 (如 001.003.012) + 遞迴 CTE / 遞迴函數MySQL 8.0+ 支援 WITH RECURSIVE
頻繁讀取、極少異動快取完整樹狀 JSON 至 Redis / 檔案,TTL 1 小時讀取效能 O(1)
需支援無限層級改用遞迴函數 buildTree($pid = 0, $level = 0)配合 level 控制縮排

一次查詢 + PHP 組裝樹狀結構(進階寫法)

<?php
$all = D('Category')->order('category_pid, sort')->select();

// 索引陣列:id => node
$map = [];
foreach ($all as $item) {
    $map[$item['category_id']] = $item;
    $map[$item['category_id']]['child'] = [];
}

// 組裝父子關聯
$tree = [];
foreach ($all as $item) {
    $pid = $item['category_pid'];
    if ($pid == 0) {
        $tree[] = &$map[$item['category_id']];
    } elseif (isset($map[$pid])) {
        $map[$pid]['child'][] = &$map[$item['category_id']];
    }
}
// $tree 即為完整巢狀結構,僅 1 次 SQL
?>

結語

ThinkPHP 兩層分類讀取的基本寫法簡單易懂,適合中小型專案。隨著資料量增長,建議改用「單次查詢 + 陣列組裝」或「資料庫路徑編碼 + 遞迴 CTE」搭配快取策略,兼顧開發效率與執行效能。

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