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

PHP 無限級分類實現:路徑存儲法完整代碼詳解

     編輯:PHP 綜合知識

核心設計思路:路徑字符串法

採用 type_p_id 字段存儲「父級路徑 + 當前 ID」的逗號分隔字符串,如 1,3,7, 表示:根節點 1 → 子節點 3 → 當前節點 7。查詢子樹只需 LIKE '1,3,7,%',極其高效。

數據表結構

CREATE TABLE `types` (
    `type_id`   INT(11)     NOT NULL AUTO_INCREMENT,
    `type_name` VARCHAR(20) NOT NULL,
    `type_p_id` VARCHAR(64) NOT NULL DEFAULT '-',
    PRIMARY KEY (`type_id`),
    KEY `type_p_id` (`type_p_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

完整功能實現(PDO 現代化重寫版)

<?php
class CategoryManager {
    private $pdo;
    
    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }
    
    /** 獲取所有分類,按層級排序 */
    public function getAll(): array {
        $stmt = $this->pdo->query("SELECT * FROM types ORDER BY type_p_id");
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    /** 添加分類 */
    public function add(string $name, int $parentId = 0): bool {
        $this->pdo->beginTransaction();
        try {
            $this->pdo->exec("INSERT INTO types (type_name) VALUES ({$this->pdo->quote($name)})");
            $id = (int)$this->pdo->lastInsertId();
            
            if ($parentId === 0) {
                $path = "$id,";
            } else {
                $stmt = $this->pdo->prepare("SELECT type_p_id FROM types WHERE type_id = ?");
                $stmt->execute([$parentId]);
                $parentPath = $stmt->fetchColumn() ?? '';
                $path = $parentPath . "$id,";
            }
            
            $this->pdo->prepare("UPDATE types SET type_p_id = ? WHERE type_id = ?")
                    ->execute([$path, $id]);
            
            $this->pdo->commit();
            return true;
        } catch (Exception $e) {
            $this->pdo->rollBack();
            return false;
        }
    }
    
    /** 遞歸刪除分類及所有子分類 */
    public function delete(int $id): bool {
        return (bool)$this->pdo->exec(
            "DELETE FROM types WHERE type_p_id LIKE " . $this->pdo->quote("$id,%")
        );
    }
    
    /** 修改分類名稱 */
    public function rename(int $id, string $newName): bool {
        return (bool)$this->pdo->prepare("UPDATE types SET type_name = ? WHERE type_id = ?")
                            ->execute([$newName, $id]);
    }
    
    /** 獲取樹狀結構數組(用於前端渲染) */
    public function getTree(): array {
        $list = $this->getAll();
        $tree = [];
        foreach ($list as $item) {
            $level = substr_count($item['type_p_id'], ',') - 1;
            $item['level'] = max(0, $level);
            $tree[] = $item;
        }
        return $tree;
    }
}
?>

前端渲染關鍵點

  • 根據 level 字段計算縮進:str_repeat('&#12288;', $level * 4)
  • 下拉選單中禁用葉子節點(substr_count($path, ',') == 1 表示無子節點)
  • 刪除操作需二次確認,防止誤刪整棵子樹

優缺點總結

優點缺點
查詢子樹極快(LIKE 前綴匹配)路徑長度受 VARCHAR(64) 限制,層級過深會截斷
移動子樹只需更新 path 前綴需應用層保證 path 一致性,無外鍵約束
無需遞歸查詢,單條 SQL 搞定不支援超過 64 字符的深層路徑

路徑存儲法適合「讀多寫少、層級固定、需快速獲取子樹」的場景,是中小型項目的首選方案。

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