php树形菜单的实现
PHP树形菜单的实现方法
实现树形菜单通常涉及数据库设计、数据查询和前端展示三个部分。以下是几种常见的实现方式:
邻接列表模型(Adjacency List)
这是最简单的树形结构存储方式,每个节点存储其父节点的ID。
// 数据库表结构示例
CREATE TABLE menu_items (
id INT PRIMARY KEY,
name VARCHAR(100),
parent_id INT NULL,
FOREIGN KEY (parent_id) REFERENCES menu_items(id)
);
递归查询实现:
function buildTree(array $elements, $parentId = 0) {
$branch = array();
foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = buildTree($elements, $element['id']);
if ($children) {
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
// 使用示例
$items = $pdo->query("SELECT * FROM menu_items")->fetchAll(PDO::FETCH_ASSOC);
$tree = buildTree($items);
嵌套集模型(Nested Set)
这种模型查询效率更高,但维护复杂。
CREATE TABLE menu_items (
id INT PRIMARY KEY,
name VARCHAR(100),
lft INT NOT NULL,
rgt INT NOT NULL
);
查询实现:
function getTree($pdo) {
$sql = "SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM menu_items AS node,
menu_items AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name, node.lft
ORDER BY node.lft";
return $pdo->query($sql)->fetchAll();
}
路径枚举(Path Enumeration)
存储从根到节点的完整路径。
CREATE TABLE menu_items (
id INT PRIMARY KEY,
name VARCHAR(100),
path VARCHAR(255) // 如 '1/4/7'
);
查询实现:
function getTree($pdo) {
$items = $pdo->query("SELECT * FROM menu_items ORDER BY path")->fetchAll();
$tree = [];
$pathMap = [];
foreach ($items as $item) {
$pathParts = explode('/', $item['path']);
$parent = &$tree;
foreach (array_slice($pathParts, 0, -1) as $part) {
$parent = &$parent['children'][$part];
}
$parent['children'][$item['id']] = $item;
$pathMap[$item['path']] = &$parent['children'][$item['id']];
}
return $tree;
}
前端展示
使用HTML和CSS展示树形结构:
function renderMenu($tree, $level = 0) {
echo '<ul class="tree level-'.$level.'">';
foreach ($tree as $node) {
echo '<li>';
echo htmlspecialchars($node['name']);
if (!empty($node['children'])) {
renderMenu($node['children'], $level + 1);
}
echo '</li>';
}
echo '</ul>';
}
// CSS样式示例
.tree ul {
list-style: none;
padding-left: 20px;
}
.tree li {
position: relative;
margin: 5px 0;
}
使用预排序遍历树算法(MPTT)
结合嵌套集模型的优化算法:
class MPTT {
private $pdo;
private $left = 'lft';
private $right = 'rgt';
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function rebuildTree($parent = 0, $left = 1) {
$right = $left + 1;
$stmt = $this->pdo->prepare("SELECT id FROM menu_items WHERE parent_id = ?");
$stmt->execute([$parent]);
while ($row = $stmt->fetch()) {
$right = $this->rebuildTree($row['id'], $right);
}
$this->pdo->prepare("UPDATE menu_items SET lft = ?, rgt = ? WHERE id = ?")
->execute([$left, $right, $parent]);
return $right + 1;
}
}
使用第三方库
可以考虑使用现有的PHP库来简化实现:
- baum/baum: Laravel的嵌套集实现
- nicmart/tree: 通用的树结构库
- doctrine-extensions: 包含树形结构扩展
示例使用baum/baum:

// 在Laravel中安装后
class Category extends Baum\Node {
protected $table = 'categories';
}
// 使用
$root = Category::create(['name' => 'Root']);
$child = Category::create(['name' => 'Child']);
$child->makeChildOf($root);
以上方法各有优缺点,邻接列表简单但查询效率低,嵌套集查询高效但维护复杂,路径枚举直观但更新困难。应根据项目需求选择合适的方法。






