无限分类实现 php
无限分类的实现方法
无限分类是一种常见的树形结构数据存储方式,适用于商品分类、部门架构等场景。以下是几种常见的实现方式:
邻接表模型(Adjacency List)
邻接表是最简单的实现方式,通过在表中添加一个parent_id字段来建立层级关系。
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT DEFAULT NULL,
FOREIGN KEY (parent_id) REFERENCES categories(id) ON DELETE CASCADE
);
查询某个分类的子分类:
function getChildren($parentId = 0) {
$db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$stmt = $db->prepare("SELECT * FROM categories WHERE parent_id = ?");
$stmt->execute([$parentId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
路径枚举法(Path Enumeration)
在表中添加一个path字段,存储从根节点到当前节点的路径。
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
path VARCHAR(255) NOT NULL
);
查询某个节点的所有子节点:
function getChildren($nodeId) {
$db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$stmt = $db->prepare("SELECT * FROM categories WHERE path LIKE ?");
$stmt->execute(["%/$nodeId/%"]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
嵌套集模型(Nested Set)
使用left和right值来表示节点在树中的位置。
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
查询某个节点的所有子节点:
function getChildren($nodeId) {
$db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$stmt = $db->prepare("SELECT node.* FROM categories AS node, categories AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND parent.id = ? ORDER BY node.lft");
$stmt->execute([$nodeId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
闭包表(Closure Table)
使用单独的表存储节点之间的关系。
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE category_relations (
ancestor INT NOT NULL,
descendant INT NOT NULL,
depth INT NOT NULL,
PRIMARY KEY (ancestor, descendant),
FOREIGN KEY (ancestor) REFERENCES categories(id),
FOREIGN KEY (descendant) REFERENCES categories(id)
);
查询某个节点的所有子节点:
function getChildren($nodeId) {
$db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$stmt = $db->prepare("SELECT c.* FROM categories c JOIN category_relations cr ON c.id = cr.descendant WHERE cr.ancestor = ? AND cr.depth > 0");
$stmt->execute([$nodeId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
递归实现无限分类
使用递归函数获取所有子分类:
function getAllCategories($parentId = 0, $level = 0) {
$db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$stmt = $db->prepare("SELECT * FROM categories WHERE parent_id = ?");
$stmt->execute([$parentId]);
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
$result = [];
foreach ($categories as $category) {
$category['level'] = $level;
$result[] = $category;
$result = array_merge($result, getAllCategories($category['id'], $level + 1));
}
return $result;
}
无限分类的前端展示
在HTML中展示无限分类:
function displayCategories($categories, $parentId = 0, $level = 0) {
echo '<ul>';
foreach ($categories as $category) {
if ($category['parent_id'] == $parentId) {
echo '<li>' . $category['name'];
displayCategories($categories, $category['id'], $level + 1);
echo '</li>';
}
}
echo '</ul>';
}
性能优化建议
对于大型分类系统,邻接表模型在查询性能上可能存在问题。嵌套集模型和闭包表在查询性能上更优,但更新操作更复杂。应根据具体需求选择合适的实现方式。

可以使用缓存机制存储分类数据,减少数据库查询次数。对于不经常变动的分类数据,可以考虑生成静态HTML或使用Redis等缓存工具。






