php 实现多级菜单
实现多级菜单的数据结构
使用递归或迭代方式构建多级菜单的核心是合理设计数据库表结构。常见方案是包含父级ID的邻接表模型:
CREATE TABLE `menu` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '菜单名称',
`parent_id` int(11) DEFAULT 0 COMMENT '父级ID,0表示一级菜单',
`sort` int(11) DEFAULT 0 COMMENT '排序权重',
`url` varchar(255) DEFAULT NULL COMMENT '菜单链接',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
递归方式生成树形结构
通过递归函数遍历所有菜单节点,构建层级关系:
function buildTree(array $elements, $parentId = 0) {
$branch = [];
foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = buildTree($elements, $element['id']);
if ($children) {
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
// 使用示例
$flatList = $db->query("SELECT * FROM menu ORDER BY sort DESC");
$tree = buildTree($flatList);
迭代方式生成树形结构
对于大数据量场景,迭代方案比递归更高效且避免栈溢出:

function buildTreeIterative(array $items) {
$tree = [];
$indexed = [];
// 建立索引
foreach ($items as $item) {
$indexed[$item['id']] = $item;
$indexed[$item['id']]['children'] = [];
}
// 构建树
foreach ($indexed as $id => $item) {
if ($item['parent_id'] == 0) {
$tree[] = &$indexed[$id];
} else {
$indexed[$item['parent_id']]['children'][] = &$indexed[$id];
}
}
return $tree;
}
前端渲染方案
将生成的树形数据通过HTML模板渲染:
function renderMenu(array $menu) {
$html = '<ul>';
foreach ($menu as $item) {
$html .= '<li>';
$html .= '<a href="'.$item['url'].'">'.$item['name'].'</a>';
if (!empty($item['children'])) {
$html .= renderMenu($item['children']);
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
echo renderMenu($tree);
性能优化建议
对于频繁读取但很少变更的菜单,建议将生成的树形结构缓存:

$cacheKey = 'menu_tree';
if (!$tree = $cache->get($cacheKey)) {
$tree = buildTree($flatList);
$cache->set($cacheKey, $tree, 3600);
}
替代方案:闭包表模型
当层级深度较大时,可考虑改用闭包表(Closure Table)存储关系:
CREATE TABLE `menu_closure` (
`ancestor` int(11) NOT NULL,
`descendant` int(11) NOT NULL,
`depth` int(11) NOT NULL,
PRIMARY KEY (`ancestor`,`descendant`)
);
查询所有子节点的SQL示例:
SELECT m.* FROM menu m
JOIN menu_closure c ON m.id = c.descendant
WHERE c.ancestor = 1 AND c.depth > 0






