PHP处理三级分类数据的三种常见实现方式
在处理后台菜单或商品类目等三级关联数据时,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处理多级分类的代码示例请关注本站其它相关文章!免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









