php 实现无限分类
无限分类的实现方法
无限分类通常用于构建多层级结构的数据,如商品分类、菜单管理等。以下是几种常见的实现方式:
邻接列表模型(Adjacency List)
这是最简单的实现方式,每个分类记录存储其父分类的ID。

// 数据库表结构示例
CREATE TABLE categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
parent_id INT DEFAULT NULL,
FOREIGN KEY (parent_id) REFERENCES categories(id)
);
// 获取所有分类
function getCategories($parentId = null) {
$categories = [];
$query = "SELECT * FROM categories WHERE parent_id " . ($parentId === null ? "IS NULL" : "= " . (int)$parentId);
$result = mysqli_query($connection, $query);
while ($row = mysqli_fetch_assoc($result)) {
$row['children'] = getCategories($row['id']);
$categories[] = $row;
}
return $categories;
}
嵌套集模型(Nested Set)
这种模型通过left和right值来表示层级关系,查询效率高但维护复杂。

CREATE TABLE categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
// 获取整个树
function getFullTree() {
$query = "SELECT * FROM categories ORDER BY lft";
$result = mysqli_query($connection, $query);
$tree = [];
$stack = [];
while ($row = mysqli_fetch_assoc($result)) {
$node = $row;
$node['children'] = [];
while (!empty($stack) && $stack[count($stack)-1]['rgt'] < $node['rgt']) {
array_pop($stack);
}
if (!empty($stack)) {
$stack[count($stack)-1]['children'][] = &$node;
} else {
$tree[] = &$node;
}
$stack[] = &$node;
}
return $tree;
}
路径枚举(Path Enumeration)
存储从根到当前节点的完整路径。
CREATE TABLE categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
path VARCHAR(255) NOT NULL
);
// 获取子分类
function getChildren($path) {
$query = "SELECT * FROM categories WHERE path LIKE '" . mysqli_real_escape_string($connection, $path) . "%'";
$result = mysqli_query($connection, $query);
$categories = [];
while ($row = mysqli_fetch_assoc($result)) {
$categories[] = $row;
}
return $categories;
}
闭包表(Closure Table)
使用单独的表存储节点之间的关系。
CREATE TABLE categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) 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 getSubtree($categoryId) {
$query = "SELECT c.* FROM categories c
JOIN category_relations cr ON c.id = cr.descendant
WHERE cr.ancestor = " . (int)$categoryId . "
ORDER BY cr.depth";
$result = mysqli_query($connection, $query);
$tree = [];
while ($row = mysqli_fetch_assoc($result)) {
$tree[] = $row;
}
return $tree;
}
性能考虑
邻接列表简单但递归查询性能差;嵌套集查询高效但写操作复杂;路径枚举适合频繁读取场景;闭包表最灵活但占用空间大。根据实际需求选择合适方案。





