PHP MySQL树结构按层级统计子节点数量并输出各层级子节点列表
树结构层级扩展实现方案
改造核心思路
原有递归遍历框架无需推翻,仅调整返回值结构,在累加层级计数的同时同步收集各层级的节点明细即可。改造后输出同时覆盖原有统计能力和新的明细查询需求,无需重构已有业务逻辑。
改造核心要点
- 调整函数返回为关联数组,固定包含两个键:
count_map:完全复用原有统计逻辑的各层级子节点计数,格式和原函数输出完全一致,兼容旧业务调用node_map:键为层级偏移序号,和count_map的键一一对应,值为对应层级的所有子节点数据行
- 保留原有的14层递归上限判断,避免数据异常导致递归过深引发栈溢出
- 递归合并子节点结果时,除了累加计数,同步将子节点的明细按层级偏移合并到当前层级的明细数组中
改造后完整代码
function childCountLevelWise($conn, $ID, $level) { // 保留原有层级上限判断,避免递归过深 if ($level > 14) { return [ 'count_map' => [0 => 0], 'node_map' => [0 => []] ]; } $sql = "select * from user_my_tree t where t.parent_ID=" . intval($ID); $result = returnResults($conn, $sql); // 无匹配子节点时返回空结构 if ($result == null) { return [ 'count_map' => [0 => 0], 'node_map' => [0 => []] ]; } // 初始化当前层结构:count_map存计数,node_map存当前层所有直属子节点 $count_map = [0 => count($result)]; $node_map = [0 => $result]; foreach ($result as $row) { // 递归获取子节点的统计和明细 $child_res = childCountLevelWise($conn, $row['ID'], $level + 1); $child_count = $child_res['count_map']; $child_nodes = $child_res['node_map']; $index = 1; // 合并子节点的计数,完全复用原有逻辑 foreach ($child_count as $cnt) { if ($cnt == 0) continue; if (isset($count_map[$index])) { $count_map[$index] += $cnt; } else { $count_map[$index] = $cnt; } $index++; } // 合并子节点的明细,层级偏移+1对应到当前层级 foreach ($child_nodes as $child_level => $nodes) { $current_level = $child_level + 1; if (empty($nodes)) continue; if (isset($node_map[$current_level])) { // 合并同层级的所有节点,用array_merge避免覆盖 $node_map[$current_level] = array_merge($node_map[$current_level], $nodes); } else { $node_map[$current_level] = $nodes; } } } return [ 'count_map' => $count_map, 'node_map' => $node_map ]; }
调用&输出示例
要查询指定根节点(比如Admin账号ID为1)的树结构,直接按原有方式调用即可
$tree_data = childCountLevelWise($conn, 1, 0); // 输出结构对应关系: // $tree_data['count_map'][0] = Admin直属子节点总数量 // $tree_data['count_map'][1] = 下一层级(直属子节点的子节点)总数量 // $tree_data['node_map'][0] = Admin直属子节点的所有数据行 // $tree_data['node_map'][1] = 下一层级的所有子节点数据行
额外优化说明
- 已对传入的ID做
intval()类型转换,避免原有SQL拼接的注入风险 - 同层级节点合并使用
array_merge,不会覆盖其他分支的子节点数据 - 完全兼容原有统计逻辑:如果旧业务只用到计数,直接取返回值中的
count_map即可,无需修改其他调用代码 - 如需精简节点展示字段,可在初始化
node_map[0]时对查询结果做字段裁剪,仅保留需要展示的内容
内容的提问来源于stack exchange,提问作者Gagandeep Singh
相关产品推荐
相关产品推荐

