PHP [Laravel] 递归统计菜单子项异常及正确终止递归方法咨询
问题原因
- 核心逻辑错误:
foreach遍历子节点时第一次循环就直接return,直接终止了整个循环和后续同级节点的处理,因此只会递归遍历第一个子节点的后代,其余同级节点完全不会被处理。 - 参数传递问题:
$limit为值传递,递归内层对$limit的修改不会同步到上层函数的计数,导致统计值无法累加。 - 函数名拼写错误:当前递归函数名为
recursiveCountChild,但代码中调用的递归函数名为dequyCountChild,无对应定义的情况下会抛出函数不存在错误。
修正方案
1. 修正后的递归函数代码
public function recursiveCountChild($parent, $gioihan, $limit = 0) { $childs = $parent->child; $limit += $childs->count(); // 达到上限直接返回,不再继续递归 if ($limit >= $gioihan) { echo "<br>Done: ".$limit; return $limit; } // 遍历所有子节点,累加计数 foreach ($childs as $item) { echo '<br>'. $item->affID.', '; // 接收递归返回的最新计数赋值给当前层级的$limit $limit = $this->recursiveCountChild($item, $gioihan, $limit); // 累加后检查是否达到上限,达到就提前终止循环避免无效消耗 if ($limit >= $gioihan) { break; } } return $limit; }
2. 逻辑说明
- 移除了
foreach内的直接return,改为接收递归返回的最新计数,保证各层级子节点的统计值可以逐层累加。 - 每处理完一个子节点的递归逻辑后就判断是否达到上限,达到就提前终止遍历,减少不必要的性能消耗。
- 修正了递归调用的函数名,确保调用的是当前定义的递归函数。
可选优化方案
如果不需要中途打断计数,想要直接统计所有后代节点的总数,可以使用Laravel的递归关联预加载实现,性能比手写递归更高:
首先在Menu模型中定义递归关联:
// 基础子菜单关联 public function children() { return $this->hasMany('App\Menu', 'parentID', 'ID'); } // 递归后代关联 public function allChildren() { return $this->children()->with('allChildren'); }
统计时直接调用即可:
$menu = Menu::with('allChildren')->where('ID', 2318)->first(); $totalChild = $menu->allChildren->flatten()->count();
内容的提问来源于stack exchange,提问作者TinhTN
相关产品推荐
相关产品推荐

