You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从含子元素的PHP数组动态生成层级菜单列表?

解决方案:将扁平分类数组转为嵌套HTML菜单

这个问题其实很常见,核心思路是先把扁平的分类数组转换成嵌套的树形结构,再通过递归遍历这个结构来生成对应的HTML列表。下面是具体的实现步骤和代码:

步骤1:构建嵌套树形结构

首先我们需要把扁平的对象数组整理成父子关联的树形结构,每个节点会包含自己的子节点集合。

// 补全你提供的原始分类数组(修正格式问题)
$flatCategories = [
    (object)[
        'CategoryID' => 4,
        'ParentCategoryID' => -1,
        'Depth' => 1,
        'Name' => 'Menu1'
    ],
    (object)[
        'CategoryID' => 2,
        'ParentCategoryID' => 4,
        'Depth' => 2,
        'Name' => 'Submenu1'
    ],
    (object)[
        'CategoryID' => 3,
        'ParentCategoryID' => 4,
        'Depth' => 2,
        'Name' => 'Submenu2'
    ],
    (object)[
        'CategoryID' => 1,
        'ParentCategoryID' => -1,
        'Depth' => 1,
        'Name' => 'Menu2'
    ]
];

// 1. 创建分类ID到节点的映射,方便快速查找父节点
$categoryMap = [];
foreach ($flatCategories as $category) {
    // 给每个节点添加children属性,用来存储子节点
    $category->children = [];
    $categoryMap[$category->CategoryID] = $category;
}

// 2. 构建树形结构
$tree = [];
foreach ($flatCategories as $category) {
    if ($category->ParentCategoryID === -1) {
        // 父ID为-1的是顶级菜单,直接加入树形根节点
        $tree[] = $category;
    } else {
        // 找到父节点,将当前节点加入父节点的children数组
        if (isset($categoryMap[$category->ParentCategoryID])) {
            $categoryMap[$category->ParentCategoryID]->children[] = $category;
        }
    }
}

步骤2:递归生成HTML菜单

有了树形结构后,我们可以写一个递归函数来遍历每个节点,输出对应的<ul>和<li>标签:

function renderMenu($nodes) {
    if (empty($nodes)) {
        return '';
    }
    
    $html = '<ul>';
    foreach ($nodes as $node) {
        // 用htmlspecialchars转义特殊字符,避免HTML注入问题
        $html .= '<li>' . htmlspecialchars($node->Name);
        // 如果当前节点有子菜单,递归渲染子菜单
        if (!empty($node->children)) {
            $html .= renderMenu($node->children);
        }
        $html .= '</li>';
    }
    $html .= '</ul>';
    
    return $html;
}

// 生成并输出最终菜单
echo renderMenu($tree);

输出结果

运行上面的代码后,你会得到完全符合需求的嵌套HTML结构:

<ul>
    <li>Menu1
        <ul>
            <li>Submenu1</li>
            <li>Submenu2</li>
        </ul>
    </li>
    <li>Menu2</li>
</ul>

补充说明

  • 这个方法的时间复杂度是O(n),效率很高,不管你的分类数组多大都能快速处理。
  • 如果你的原始数组里可能存在无效的父ID(比如父ID对应的分类不存在),可以在构建树形结构时加个判断跳过这些节点,避免报错。
  • htmlspecialchars()是必要的安全处理,能防止菜单名称里的特殊字符(比如<、>)破坏HTML结构。

内容的提问来源于stack exchange,提问作者Tim Döring

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:12:52