php无限分类的实现
PHP无限分类的实现方法
无限分类(也称为多级分类或树状分类)是一种常见的数据结构需求,适用于商品分类、文章分类等场景。以下是几种实现方式:
邻接列表模式(Adjacency List)
这是最简单的实现方式,通过父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)
通过存储完整路径来优化查询效率:
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
path VARCHAR(255) NOT NULL COMMENT '如1/2/3'
);
查询子分类示例:
// 查询ID为5的分类的所有子分类
$result = mysqli_query($conn, "SELECT * FROM categories WHERE path LIKE '5/%'");
嵌套集模式(Nested Set)
通过左右值编码实现高效查询:
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
查询子树示例:
// 获取ID为5的分类及其所有子分类
$node = mysqli_fetch_assoc(mysqli_query($conn, "SELECT lft, rgt FROM categories WHERE id = 5"));
$result = mysqli_query($conn,
"SELECT * FROM categories WHERE lft BETWEEN {$node['lft']} AND {$node['rgt']} ORDER BY lft"
);
闭包表模式(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 getAllDescendants($categoryId) {
$query = "SELECT c.* FROM categories c
JOIN category_relations cr ON c.id = cr.descendant
WHERE cr.ancestor = $categoryId AND cr.descendant != $categoryId";
return mysqli_query($conn, $query);
}
性能对比
- 邻接列表:简单易实现,但递归查询性能较差
- 路径枚举:查询效率高,但维护路径复杂
- 嵌套集:查询效率最高,但插入/移动节点成本高
- 闭包表:查询和维护都较高效,但需要额外表
实际应用建议
对于中小型项目,推荐使用邻接列表+缓存的方式:
// 使用缓存存储整个分类树
function getCategoryTree() {
$cacheKey = 'category_tree';
if ($tree = cache_get($cacheKey)) {
return $tree;
}
$tree = buildTreeFromDB();
cache_set($cacheKey, $tree, 3600);
return $tree;
}
对于大型系统,建议考虑嵌套集或闭包表实现,必要时可以结合Elasticsearch等搜索引擎优化查询性能。







