不使用递归PHP迭代父级子级


Iterate parent children without using recursive PHP

我有一个数据库表,父-子行,一个父-多个子,由字段"parent"链接。

我知道如何在PHP中使用递归函数来循环和打印一个jerarquy结构,但是当我试图用单个循环代码来重现它时,我无法以相同的格式呈现数据。这个代码示例列出了数据库表中的所有项目,但不是按顺序排列的,它首先打印顶层,我想要经典的:

  Top 1 >> Level 1 >> Level 2 >> Level 3
  Top 2 >> Level 1
  Top 3 >> Level 1 >> Level 2
  $parent = array();
  array_push($parent, 0);
  while(!empty($parent)){
    foreach($parent as $key => $mother){
      unset($parent[$key]);     
      $sql = "SELECT * FROM levels WHERE parent = " . $mother;
      $res = mysql_query($sql);
      while($row=mysqli_fetch_object($res)){
        print $row->name . "<br />";
        array_push($parent, $row->id);
      } // while
    } // foreach
  } // while

这个代码的结果是

1前2前三1级div…

这里最大的问题是为什么要用非递归的方式?考虑到你有多个,似乎是一个未确定的,层次的子节点,这正是递归函数擅长的。

只使用简单的循环,你需要有尽可能多的嵌套循环,因为有层次的子;或者,跟踪当前节点ID,前一个节点ID和父节点ID (复数形式),然后使用它来确定是否要创建一个新的叶子,退出一个叶子或保持不变。
基本上:

Same parent == same leaf
Different parent && parent == previous id, new leaf
Different parent { when (parentList[idx--] == parent) == change leaf to idx leaf.

在这两个方法中,后一个是迄今为止最可扩展的,并且只需要两个循环:一个主循环用于所有元素,一个内部循环用于回滚到树中,直到找到正确的父ID。基本上,通过使用递归函数来模拟你自然得到的一切。

我想评论的另一件事是你在循环中使用查询。这样做通常是非常糟糕的,因为它会成倍地增加代码的时间消耗。最好在一个查询中获取所有节点,并按父节点和ID排序。这样,您就不必等待(n-1)*y ms(或更多)额外的时间,其中n是记录的数量,y是运行查询一次所需的时间。
如果查询运行时间为20毫秒,并且您有300条记录,那么您将花费近6秒的额外等待时间!这仅仅是因为您将查询移到了循环中,而没有对其进行正确排序(或使用join)。
正如您所看到的,通过正确地构建代码可以获得很多性能。不仅如此,它还会更容易阅读和维护您的代码。

总结:使用递归函数,因为这是它们的目的,并将查询移出循环。