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

PHP 遞迴處理多維陣列:樹狀結構建構實作

     編輯:PHP 相關知識

PHP 遞迴處理多維陣列:樹狀結構建構實作

處理無限分類、選單、組織架構等樹狀資料時,遞迴是核心技巧。本文示範如何從扁平資料庫結果建構巢狀陣列樹,並提供兩種常見遞迴模式。

資料結構假設

資料表 otoarea:

欄位說明
tid主鍵 ID
oid父節點 ID (0 為根)
areaname節點名稱

遞迴函數實作

<?php
class AreaService {
    private $db;

    public function __construct(PDO $db) {
        $this->db = $db;
    }

    /**
     * 遞迴建構樹狀結構
     * @param int $parentId 父節點 ID
     * @return array 巢狀陣列
     */
    public function buildTree(int $parentId = 0): array {
        // 1. 取得直屬子節點
        $stmt = $this->db->prepare("SELECT tid, areaname FROM otoarea WHERE oid = ?");
        $stmt->execute([$parentId]);
        $children = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $tree = [];
        foreach ($children as $child) {
            $node = [
                'node'  => $child['areaname'],
                'value' => $child['tid'],
            ];

            // 2. 遞迴取得子孫節點
            $descendants = $this->buildTree($child['tid']);
            if (!empty($descendants)) {
                $node['nodes'] = $descendants;
            }

            $tree[] = $node;
        }
        return $tree;
    }
}

// 使用方式
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass');
$service = new AreaService($pdo);
$tree = $service->buildTree(0); // 從根節點開始
echo json_encode($tree, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
?>

輸出範例

[
  {
    "node": "台灣",
    "value": 1,
    "nodes": [
      {
        "node": "台北市",
        "value": 2,
        "nodes": [
          { "node": "信義區", "value": 5 },
          { "node": "大安區", "value": 6 }
        ]
      },
      {
        "node": "高雄市",
        "value": 3
      }
    ]
  }
]

效能優化:單次查詢 + 記憶體組裝(大量資料適用)

遞迴查詢會產生 N+1 次 SQL,資料量大時極慢。改為一次查詢全表,PHP 組裝:

<?php
function buildTreeOptimized(PDO $db, int $rootId = 0): array {
    // 1. 一次撈取所有節點
    $stmt = $db->query("SELECT tid, oid, areaname FROM otoarea");
    $all = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // 2. 建立 ID => 節點映射,並初始化 children 陣列
    $map = [];
    foreach ($all as $row) {
        $map[$row['tid']] = [
            'node'  => $row['areaname'],
            'value' => $row['tid'],
            'nodes' => [],
        ];
    }

    // 3. 依父子關係掛載
    $tree = [];
    foreach ($all as $row) {
        $id = $row['tid'];
        $pid = $row['oid'];
        if ($pid == $rootId) {
            $tree[] = &$map[$id]; // 根節點直接放入樹
        } elseif (isset($map[$pid])) {
            $map[$pid]['nodes'][] = &$map[$id]; // 掛載到父節點
        }
        // 孤兒節點(父不存在)可選擇忽略或放入特殊陣列
    }
    return $tree;
}
?>

兩種模式對比

維度遞迴查詢單次查詢組裝
SQL 次數O(N) 次 (N=節點數)1 次
記憶體低O(N)
程式碼複雜度低中
適用資料量< 1000 節點任意大小
即時性最高 (每次查最新)需重新查詢更新

輸出為 HTML 選單(遞迴渲染)

<?php
function renderTree(array $tree): string {
    $html = '<ul>';
    foreach ($tree as $node) {
        $html .= '<li>' . htmlspecialchars($node['node']);
        if (!empty($node['nodes'])) {
            $html .= renderTree($node['nodes']);
        }
        $html .= '</li>';
    }
    $html .= '</ul>';
    return $html;
}

echo renderTree($tree);
?>

遞迴深度限制與安全

  • PHP 預設無遞迴深度限制,但極深樹會導致堆疊溢位
  • 可加入深度參數防禦:buildTree($pid, $depth = 0),超過 100 層拋出異常
  • 資料庫層面建議加入 CHECK (oid != tid) 防止自我循環

希望本文助您掌握 PHP 陣列樹狀結構建構與渲染技巧。

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