
本文介绍如何将深度未知的多层嵌套树(含 children 属性的对象数组)通过递归方式扁平化提取,按 depth 键分组聚合 tid 值,替代硬编码的多层 foreach,提升代码可维护性与健壮性。
本文介绍如何将深度未知的多层嵌套树(含 children 属性的对象数组)通过递归方式扁平化提取,按 depth 键分组聚合 tid 值,替代硬编码的多层 foreach,提升代码可维护性与健壮性。
在处理树形结构数据(如分类目录、组织架构、评论嵌套等)时,常遇到深度动态变化的问题:$tree 是一个对象数组,每个元素包含 tid(ID)、depth(层级)和可选的 children(子节点数组)。原始代码使用多达六层嵌套 foreach,不仅冗长难读,更无法应对任意深度——一旦新增层级,就必须手动扩展循环,严重违背开闭原则。
理想的解决方案是递归遍历 + 引用传参:定义一个递归函数,对当前层级每个节点提取 $val->tid 并存入 $data[$val->depth][],再对其 $val->children 递归调用自身。关键点在于:
- 使用 &$data 引用传递,确保所有递归层级共享同一结果容器;
- 显式校验 is_object($val) 和 !empty($val->children),避免访问不存在属性或空值报错;
- 封装入口函数 func_handler(),隐藏引用细节,保持调用简洁。
以下是完整、健壮、生产可用的实现:
/**
* 递归收集树节点 tid,按 depth 分组
* @param array|object $item 当前层级节点集合(通常为对象数组)
* @param array &$data 引用传递的结果容器:$data[$depth] = [tid1, tid2, ...]
* @return void
*/
function collectTermsByDepth($item, &$data) {
// 安全防护:跳过空值、非数组/非对象
if (empty($item)) {
return;
}
// 确保是可遍历结构(兼容数组或 Traversable 对象)
if (!is_array($item) && !($item instanceof Traversable)) {
return;
}
foreach ($item as $val) {
// 跳过非对象节点(如 null 或标量)
if (!is_object($val)) {
continue;
}
// 提取并存储 tid(需确保属性存在)
if (property_exists($val, 'tid') && property_exists($val, 'depth')) {
$depth = (int)$val->depth;
$data[$depth][] = $val->tid;
}
// 递归处理子树(children 可能为 null、空数组或对象数组)
if (property_exists($val, 'children') && !empty($val->children)) {
collectTermsByDepth($val->children, $data);
}
}
}
/**
* 入口函数:接收树根节点,返回按 depth 分组的 tid 数组
* @param array|object $tree 树的根节点(通常是对象数组)
* @return array 形如 [$depth => [$tid, ...], ...]
*/
function buildTermMap($tree) {
$result = [];
collectTermsByDepth($tree, $result);
ksort($result); // 可选:按 depth 升序排列键,保证输出有序
return $result;
}
// ✅ 使用示例:
// $termMap = buildTermMap($tree);
// print_r($termMap);
注意事项与最佳实践:
- ✅ 健壮性增强:添加 property_exists() 检查,避免 Undefined property 警告;ksort() 确保结果按 depth 自然排序,符合预期输出格式;
- ⚠️ 性能提示:该递归为深度优先(DFS),时间复杂度 O(n),空间复杂度 O(d)(d 为最大深度),对绝大多数业务树结构足够高效;
- ? 避免常见错误:切勿在递归中 return $data —— 引用传参无需返回;不要在 foreach 内部修改 $item 结构,否则可能引发不可预知行为;
- ? 调试建议:若结果为空,优先检查 $tree 数据结构是否真实包含 children 属性(注意大小写、JSON 解码后是否为对象而非数组)。
通过此方案,无论树深是 2 层还是 20 层,代码均无需修改,真正实现“一次编写,任意深度适配”,是处理动态树结构的推荐范式。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











