2014-06-29 72 views
1

我不習慣遞歸函數,我不明白如何正確地退出函數。PHP遞歸中斷

我嘗試從數據庫中的父項目(使用Laravel)中識別出一個兒童(祖孫,等等)的列表。

public function getChildren($parentId, $allChildrenArray = Array()){ 
    $children = DB::table('myTable')->where('parent',$parentId)->get(); 
    if (sizeof($children)>0){ 
     foreach ($children as $child) { 
      array_push($allChildrenArray,array($child->slug, $child->id)); 
      MyController::getChildren($child->id, $allChildrenArray); 
     } 
    }else{ 
     // var_dump($allChildrenArray); displays a proper array 
     return $allChildrenArray; 
    } 
} 

我對此有兩個問題。

  1. 據我瞭解我的腳本,它會停止繁殖,只要遇到死衚衕。但是,如果還有其他方法需要探索,該怎麼辦?
  2. 如果我顯示一個var_dump($allChildrenArray),顯示的數組看起來好像沒問題。 不過,如果我嘗試從其他功能顯示它,我得到null ...

    public function doStuff($itemId){ 
        $allChildrenArray = MyController::getChildren($itemId); 
        var_dump($allChildrenArray); // displays null 
    } 
    
+0

理解它的最簡單方法是在紙上手動執行所有步驟。 「我得到'null'」---因爲如果sizeof($ children)> 0',你不會返回任何東西。你還沒有使用'MyController :: getChildren'調用的結果。 – zerkms

+0

但是如果'sizeof($ children)> 0',如果有孩子,我更新'$ allChildrenArray'的值。然後,我只用兒童數組的更新值和更新後的參考項目重新啓動同樣的事情。我應該返回什麼? – Yako

+0

「我更新了$ allChildrenArray的值」---並且什麼都不做。你修改了一個變量,然後呢?它不是在你最初通過它的地方神奇地修改過。 – zerkms

回答

2

首先,你應該把你的助手你的控制器:)

更多的外要點:瞭解遞歸有助於逐步處理,並且當你進入遞歸時,假設我們假設它正在做它以後應該返回的東西。

讓我們開始像這樣:

/** 
    * Returns the children for a given parent 
    * @param int $parentId 
    * @return array 
    */ 
    public function getChildren($parentId){ 
     $allChildrenArray = array(); 
    $children = DB::table('myTable')->where('parent',$parentId)->get(); 
     foreach ($children as $child) { 
     array_push($allChildrenArray, array($child->slug, $child->id)); 
     // Here should be the recursion later 
     } 
     // var_dump($allChildrenArray); displays a proper array 
     return $allChildrenArray; 
    } 

現在,如果你看一下這個功能,你會看到它適用於第一級。很容易判斷,如果要添加遞歸,在通過給定父項的子元素時,需要獲取這些子元素。

/** 
    * Returns the children recursively for a given parent 
    * @param int $parentId 
    * @return array 
    */ 
    public function getChildren($parentId){ 
     $allChildrenArray = array(); 
     $children = DB::table('myTable')->where('parent',$parentId)->get(); 
     foreach ($children as $child) { 
     array_push($allChildrenArray, array($child->slug, $child->id)); 
     // get descendants of child 
     $furtherDescendants = $this->getChildren($child->id); 
     // add them to current list 
     foreach ($furtherDescendants as $desc) { 
      $allChildrenArray[] = $desc; // or use arraypush or merge or whatever 
     } 
     } 
     // var_dump($allChildrenArray); displays a proper array 
     return $allChildrenArray; 
    } 

現在發生的事情是,當你到達第一個孩子的getChildren功能的新的運行將開始爲孩子的父ID的ID。如果沒有它的孩子,那麼它會返回一個空數組,否則它會添加該孩子的信息,然後開始一個新的作爲父母的身份證號的孫ID和...

你可以如果你傳遞數組,可能會保存一些內存,但在這種情況下,你需要將它作爲參考。此外,當你首先調用這個方法時,你需要傳遞一個變量作爲一個輸入來填充。

/** 
    * Returns the children recursively for a given parent 
    * @param int $parentId 
    * @param &array $children 
    */ 
    public function getChildren($parentId, &$allChildrenArray) { 
     $children = DB::table('myTable')->where('parent',$parentId)->get(); 
     foreach ($children as $child) { 
     array_push($allChildrenArray, array($child->slug, $child->id)); 
     // get descendants of child 
     $this->getChildren($child->id, $allChildrenArray); 
     } 
     // var_dump($allChildrenArray); displays a proper array 
     return; // nothing to return, children info added to variable passed by reference 
    } 

    ... 

     $kids=array(); 
     $this->getChildren($parentId, $kids); 
     var_dump($kids) 

只要確保您不混淆兩種不同的解決方案。

退出條件將是一個給定的父母沒有孩子的情況。在這種情況下,foreach不會啓動,因此不會進行進一步的遞歸調用。但是,這隻意味着退出該分支。

+0

非常感謝您提供這個非常全面的答案! – Yako