PHP处理三级分类数据的三种常见实现方式

Chloe
Chloe
发布时间:2026-10-13| 5人浏览过
原创

在处理后台菜单或商品类目等三级关联数据时,PHP通常需要将平面或原始结构转换为标准树形JSON。本文整理了处理此类数据的三种典型场景及对应代码:针对已知结构的嵌套数组重组、基于数据库字段的路径解析法,以及通用的递归构建法。

结果或目标:获取标准树形结构

在处理包含三级信息的复杂数组时,最终目标是获得一个格式统一、层级清晰的数组($level_1_tree)。每个节点通常包含基础属性以及子节点列表,便于前端渲染为侧边栏菜单或表格。以下代码展示了如何从原始数据结构转换为所需的输出结构。

准备条件:原始数据定义

首先需要明确输入的数据源。此处采用函数返回的嵌套数组作为样例,模拟了系统管理中的菜单配置。注意,此处的数据结构中包含了component、redict、path、hidden以及name等多个字段,且部分叶子节点未设置children属性。

function getDatas(){
    return [
	[
		'component' => 'system',
		'redict' => '/system',
		'path' => '/system',
		'hidden' => 1,
		'name' => '系统管理',
		'children' => [
			[
				'component' => 'user',
				'redict' => '/user',
				'path' => '/user',
				'hidden' => 1,
				'name' => '用户管理',
				'children' => [
					[
						'component' => 'user_list',
						'redict' => '/user_list',
						'path' => '/user_list',
						'hidden' => 1,
						'name' => '用户列表',
					],
					[
						'component' => 'role',
						'redict' => '/user_role',
						'path' => '/user_role',
						'hidden' => 1,
						'name' => '角色列表',
					],
					[
						'component' => 'perm',
						'redict' => '/perm',
						'path' => '/perm',
						'hidden' => 1,
						'name' => '权限列表',
					],
				]
			],
			[
				'component' => 'data',
				'redict' => '/data',
				'path' => '/data',
				'hidden' => 1,
				'name' => '数据管理',
				'children' => [
					[
						'component' => 'report',
						'redict' => '/report',
						'path' => '/report',
						'hidden' => 1,
						'name' => '分日报表',
					],
					[
						'component' => 'hour_report',
						'redict' => '/hour_report',
						'path' => '/hour_report',
						'hidden' => 1,
						'name' => '分时报表',
					],
					[
						'component' => 'month_report',
						'redict' => '/month_report',
						'path' => '/month_report',
						'hidden' => 1,
						'name' => '分月报表',
					],
				]
			],
			[
				'component' => 'resource',
				'redict' => '/resource',
				'path' => '/resource',
				'hidden' => 1,
				'name' => '资源管理',
				'children' => [
					[
						'component' => 'res_list',
						'redict' => '/res_list',
						'path' => '/res_list',
						'hidden' => 1,
						'name' => '资源列表'
					]
				]
			]
		]
	]
]
}

真实操作顺序:逐级遍历与映射重构

本方法通过三次循环分别处理第一级、第二级和第三级数据。主要目的是将原始数据中的 name 和 hidden 字段映射到新结构中统一的 meta 对象下,并剥离无效的子节点键值,确保最终输出的数组干净。

第1步:初始化外层容器并提取一级节点信息

首先调用 getDatas() 获取原始数据,新建空数组 $level_1_tree 用于存储结果。遍历每一组一级数据,逐一提取 component、redict 和 path。同时,创建新的 meta 数组,将原字段的 name 赋值为 title,并将 hidden 值同步。这一步确保了数据结构的一致性。

$datas = getDatas();
$level_1_tree = [];
foreach($datas as $data_level_1){
    $data_level_1_arr['component'] = $data_level_1['component'];
    $data_level_1_arr['redict'] = $data_level_1['redict'];
    $data_level_1_arr['path'] = $data_level_1['path'];
    $data_level_1_arr['meta'] = [
         'title' => $data_level_1['name'],
         'hidden' => $data_level_1['hidden']
    ];

第2步:循环处理二级节点及其潜在子项

检查当前一级节点是否包含 children。如果存在,初始化 $level_2_tree 并遍历二级数据。同样提取基本字段并生成对应的 meta。随后,初始化 $level_3_tree 用于承接下一层级。此处需注意,即使没有三级子项,也要保证后续流程不报错。

    $level_2_tree = [];
    if(isset($data_level_1['children']) && !empty($data_level_1['children'])) {
        foreach ($data_level_1['children'] as $data_level_2) {
            $data_level_2_arr['component'] = $data_level_2['component'];
            $data_level_2_arr['redict'] = $data_level_2['redict'];
            $data_level_2_arr['path'] = $data_level_2['path'];
            $data_level_2_arr['meta'] = [
             'title' => $data_level_2['name'],
             'hidden' => $data_level_2['hidden']
            ];
            $level_3_tree = [];

第3步:处理三级叶子节点并回填层级

在二级节点的循环内部,检查是否存在 children。若存在,则进入三级节点的深层遍历,逐个提取字段填入 $data_level_3_arr 并通过 array_push 加入 $level_3_tree。每次加入后使用 unset 释放内存引用,防止变量污染。完成三级遍历后,将生成的 $level_3_tree 赋值给当前二级节点的 children。接着将整理好的二级节点推入 $level_2_tree,最后将整个二级树组分配给一级节点。

                    if (isset($data_level_2['children']) && !empty($data_level_2['children'])) {
                       
                       foreach ($data_level_2['children'] as $data_level_3) {
                            $data_level_3_arr['component'] = $data_level_3['component'];
                            $data_level_3_arr['redict'] = $data_level_3['redict'];
                            $data_level_3_arr['path'] = $data_level_3['path'];
                            $data_level_3_arr['meta'] = [
                               'title' => $data_level_3['name'],
                               'hidden' => $data_level_3['hidden']
                            ];
                            array_push($level_3_tree, $data_level_3_arr);
                            unset($data_level_3_arr);
                       }
                       $data_level_2_arr['children'] = $level_3_tree;
                    }
                    array_push($level_2_tree, $data_level_2_arr);
                    unset($data_level_2_arr);
                }
                $data_level_1_arr['children'] = $level_2_tree;
            }
            
            array_push($level_1_tree, $data_level_1_arr);
            unset($data_level_1_arr);
        }
        print_r($level_1_tree);
    }

  deal();

完成判断:验证输出结构

运行上述代码后,可以通过打印结果观察生成的 $level_1_tree。该数组应严格符合预定义的层级深度,即最多包含两级 children 嵌套(一级->二级->三级)。任何缺失的层级均不应出现在最终的输出列表中,且所有节点都应包含完整的 meta 信息。

原文有依据的排错与替代方案

对于不同的数据来源(如直接从数据库获取),上述手动遍历方法可能不适用。以下是两种常见的替代处理方式,供不同需求参考:

基于数据库字段的层级解析法

如果数据存储在数据库中,且存在表示层级的字段(如 categorys_path 以逗号分隔的路径字符串),可以使用解析法快速组装树形结构。此方法适用于层级固定且较浅的场景,通过解析路径字符串来确定父节点和子节点的归属关系。

<?php
// 链接数据库
$link = mysqli_connect('localhost','root','root');
if($link == null){
    exit;
}
mysqli_select_db($link,'test');
$link->query("SET NAMES utf8");
$sql = "select * from tp_goods_categorys";
$res = mysqli_query($link,$sql);
while($res && $row = mysqli_fetch_assoc($res)) {
  $list[] = $row;
}
echo '<pre>';
print_r(res($list)); 
function res($items){
    $tree = array();
    foreach($items as $key =>$val){
            $list = explode(',',$val['categorys_path']);
            switch(count($list)){
                case 1:
                    $tree[$val['id']] = $val;
                    break;
                case 2:
                    $tree[$val['categorys_pid']]['son'][$val['id']] = $val;
                    break;
                case 3:
                    $tree[$list[1]]['son'][$list[2]]['son'] = $val;
                    break;
            }
    }
    return $tree;
}
?

通用递归建树法

当数据是一维数组但带有 pid(父ID)标识时,递归是最灵活的方案。该方法不仅适用于三级,理论上可处理任意深度的分类。通过查找所有父ID匹配的节点,并为其动态添加 son 键值来构建树。

<?php
$array = array(
array('id' => 1, 'pid' => 0, 'name' => '湖北省'),
array('id' => 2, 'pid' => 0, 'name' => '北京市'),
array('id' => 3, 'pid' => 1, 'name' => '武汉市'),
array('id' => 4, 'pid' => 2, 'name' => '朝阳区'),
array('id' => 5, 'pid' => 2, 'name' => '通州区'),
array('id' => 6, 'pid' => 4, 'name' => '望京'),
array('id' => 7, 'pid' => 4, 'name' => '酒仙桥'),
array('id' => 8, 'pid' => 3, 'name' => '武昌区'),
array('id' => 9, 'pid' => 1, 'name' => '武安市'),
);
function cation($arr,$num=0,$m=1)
{
    $list = [];
    foreach($arr as $k=>$v){
        if($v['pid'] === $num){
            $v['level'] = $m;
            $v['son'] = cation($arr,$v['id'],$m+1);
            $list[] = $v;
        }
    }
    return $list;
}
$list = cation($array);
echo '<pre>';
print_r($list);
echo '</pre>';
?

扁平化重组(一维数组转带层级的一维列表)

另一种常见需求是将树形结构展平为一维数组,但在每个元素中标注其层级信息(level)。这常用于生成下拉选择框选项或表格行数据。该方法通过静态变量保存中间结果,并使用递归来按层级顺序排列。

//    处理分类数据 栏目分级
public function allMenu($cates,$pid=0,$level=0){
    static $cateArr = array();
    for($i=0;$i<count($cates);$i++){
        if($cates[$i]['pid']==$pid){
            $cates[$i]['level']=$level;
            $cateArr[]=$cates[$i];
            $this->allMenu($cates,$cates[$i]['id'],$level+1);
        }
    }
    return $cateArr;
}
以上就是PHP实现处理三级分类数据的详细内容,更多关于PHP处理多级分类的代码示例请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。