php无限分类的实现
PHP无限分类的实现方法
无限分类(又称树形分类或多级分类)是常见的需求,例如商品分类、地区划分等。以下是几种实现方式:
邻接表模型(Adjacency List)
邻接表是最简单的实现方式,通过parent_id字段记录父级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)
);
递归查询子分类:
function getChildren($parentId = 0) {
$categories = [];
$result = mysqli_query($conn, "SELECT * FROM categories WHERE parent_id = $parentId");
while ($row = mysqli_fetch_assoc($result)) {
$row['children'] = getChildren($row['id']);
$categories[] = $row;
}
return $categories;
}
路径枚举(Path Enumeration)
通过path字段存储从根到当前节点的路径(如1/3/5)。

CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
path VARCHAR(255) NOT NULL
);
查询某个节点的所有子节点:
function getDescendants($categoryId) {
$result = mysqli_query($conn, "SELECT path FROM categories WHERE id = $categoryId");
$path = mysqli_fetch_assoc($result)['path'];
return mysqli_query($conn, "SELECT * FROM categories WHERE path LIKE '$path/%'");
}
嵌套集模型(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) {
$node = mysqli_fetch_assoc(mysqli_query($conn, "SELECT lft, rgt FROM categories WHERE id = $nodeId"));
return mysqli_query($conn, "SELECT * FROM categories WHERE lft > {$node['lft']} AND rgt < {$node['rgt']}");
}
闭包表(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 getDescendants($categoryId) {
$query = "SELECT c.* FROM categories c
JOIN category_relations cr ON c.id = cr.descendant
WHERE cr.ancestor = $categoryId AND cr.depth > 0";
return mysqli_query($conn, $query);
}
实际应用建议
- 简单需求:邻接表最容易实现,适合层级较少的情况
- 频繁查询:嵌套集或闭包表性能更好,但写入成本较高
- 层级深度:路径枚举适合已知最大深度的情况
每种方法各有优劣,需根据具体场景选择。邻接表最易理解但查询效率低,闭包表最灵活但占用空间大。






