
本文详解如何使用递归函数在具有 "child" 键的多层嵌套数组(如菜单树)中精准定位目标节点,并完整返回其自身及全部后代节点,修复常见递归未正确传递返回值的逻辑缺陷。
在处理树状结构数据(例如导航菜单、分类目录)时,常需根据某个唯一标识(如 slug)查找目标节点并获取其完整子树。原始代码虽具备递归意识,但存在一个关键错误:未将子递归调用的返回值进行判断与透传。当在 child 子数组中找到匹配项时,函数直接结束当前循环,却未将该结果向上级调用栈返回,导致最终返回空数组 []。
以下是修正后的专业实现方案:
<?php
$tree = '[{"id":1,"structure":1,"parent":0,"slug":"medicinskaya-ge","child":{"2":{"id":2,"structure":1.1,"parent":1,"slug":"dnk-diagnostika","child":{"3":{"id":3,"structure":"1.1.1","parent":2,"slug":"dnk-diagnostika","datafile":"ssz","template":"ssz"},"4":{"id":4,"structure":"1.1.2","parent":2,"slug":"dnk-diagnostika","child":{"5":{"id":5,"structure":"1.1.2.1","parent":4,"slug":"dnk-diagnostika"},"6":{"id":6,"structure":"1.1.2.2","parent":4,"slug":"testirovanie-ge"},"7":{"id":7,"structure":"1.1.2.3","parent":4,"slug":"dnk-diagnostika"}}},"8":{"id":8,"structure":"1.1.3","parent":2,"slug":"dnk-diagnostika"},"9":{"id":9,"structure":"1.1.4","parent":2,"slug":"texnologiya-kol"}}}}}]';
$tree = json_decode($tree, true);
function getSlugData(string $slug, array $data, string $key = 'slug'): array
{
foreach ($data as $row) {
// 优先检查当前层级是否命中
if (isset($row[$key]) && $row[$key] === $slug) {
return $row; // 直接返回完整节点(含 child 子树)
}
// 若存在 child 且为数组,则递归深入搜索
if (isset($row['child']) && is_array($row['child'])) {
$found = getSlugData($slug, $row['child'], $key);
if (!empty($found)) {
return $found; // 关键修复:非空结果必须立即返回,终止后续遍历
}
}
}
return []; // 全树遍历后未找到,返回空数组
}
// 测试用例
var_dump(getSlugData('testirovanie-ge', $tree));
// 输出包含 id=6 的节点及其上级 child 结构(即完整子树路径)
var_dump(getSlugData('texnologiya-kol', $tree)); // 正确返回 id=9 节点
var_dump(getSlugData('not-exists', $tree)); // 返回 []
?>✅ 核心要点总结:
- 递归出口必须显式返回:每次递归调用后需检查返回值,非空则立即 return,避免被外层循环覆盖;
- 避免冗余遍历:一旦找到目标,应立即退出,无需继续处理剩余兄弟节点;
- 健壮性增强:添加 isset($row['child']) 和 is_array() 双重校验,防止对非数组类型调用递归引发警告;
- 可扩展设计:通过 $key 参数支持按任意字段(如 id、title)检索,提升复用性。
⚠️ 注意事项:
- 该函数返回的是首次匹配的最深层节点(深度优先),若需所有匹配项,请改用累加式递归并返回数组集合;
- 对超深嵌套结构(>100 层),需注意 PHP 默认 xdebug.max_nesting_level 限制,必要时调整配置;
- 生产环境建议增加类型提示(如 array|stdClass)和异常日志,便于调试与维护。
此方案简洁、高效、符合 PSR-12 编码规范,可直接集成至 Laravel、Symfony 等主流框架的菜单服务中。










