2012-10-30 62 views
2

我想玩一些PHP的迭代器,並設法得到一個堅實的(從我的理解)建設去。我的目標是在父文件夾內迭代並獲取2個節點;在這個過程中建立一個分層的樹型數組。很明顯,我可以使用glob和一些嵌套循環來很容易地完成這個任務,但是我想使用Spl類來完成這個任務。SplRecurisveDirectoryIterator&分層數組

所有這一切,我已經玩過SplHeap和SplObjectStore到層次結構和失敗。和我的麪條混淆的是我常規的遞歸方法失敗(內存不足錯誤),我的一個成功歸結於循環遍歷每個節點的遞歸方法,並添加到數組中。問題在於它忽略了setMaxDepth()方法並遍歷所有的孩子。我想過設置一個$ var ++通過循環增加,限制節點,但我不認爲這是「正確的方式」。

Anywho,代碼(對不起,如果有任何孤立的代碼 - 只是忽略它)...

<?php 
namespace Tree; 

use RecursiveFilterIterator, 
    RecursiveDirectoryIterator, 
    RecursiveIteratorIterator; 

class Filter extends RecursiveFilterIterator { 
    public static $FILTERS = array(
     '.git', '.gitattributes', '.gitignore', 'index.php' 
    ); 

    public function accept() { 
     if (!$this->isDot() && !in_array($this->current()->getFilename(), self::$FILTERS)) 
      return TRUE; 

     return FALSE; 
    } 
} 

class DirTree { 
    const MAX_DEPTH = 2; 

    private static $iterator; 
    private static $objectStore; 

    public function __construct() { 

     error_reporting(8191); 
     $path  = realpath('./'); 

     try { 

      $dirItr  = new RecursiveDirectoryIterator($path); 
      $filterItr = new Filter($dirItr); 
      $objects = new RecursiveIteratorIterator($filterItr, RecursiveIteratorIterator::SELF_FIRST); 

      $objects->setMaxDepth(self::MAX_DEPTH); 

      echo '<pre>'; 
      print_r($this->build_hierarchy($objects)); 

     } catch(Exception $e) { 
      die($e->getMessage()); 
     } 
    } 

    public function build_hierarchy($iterator){ 
     $array = array(); 
     foreach ($iterator as $fileinfo) { 

      if ($fileinfo->isDir()) { 
       // Directories and files have labels 
       $current = array(
        'label' => $fileinfo->getFilename() 
       ); 
       // Only directories have children 
       if ($fileinfo->isDir()) { 
        $current['children'] = $this->build_hierarchy($iterator->getChildren()); 
       } 
       // Append the current item to this level 
       $array[] = $current; 
      } 
     } 
     return $array; 
    } 
} 

$d = new DirTree; 

回答

1

一個RecursiveIteratorIterator設計主要是爲了給你在一個平面列表的行爲就像一個迭代的迭代器,但是扁平列表實際上只是遞歸遍歷中的一個序列。它通過內部管理一個RecursiveIterators堆棧來完成,根據需要調用getChildren()。 RecursiveIteratorIterator的客戶端是唯一真正應該調用正常Iterator方法,如current()next()等等與增值的方法,如setMaxDepth()

你的問題的例外是,您試圖通過調用getChildren()自己做遞歸。如果你想手動管理遞歸,那很好 - 但這使得RecursiveIteratorIterator是多餘的。其實我真的很驚訝,撥打getChildren()RecursiveIteratorIterator沒有致命錯誤。這是一個RecursiveIterator方法。 spl可能只是將方法調用轉發給內部迭代器(一些spl類將方法調用轉發給未定義的方法,以便使用Decorator設計模式)。

正確的做法:

$dirItr  = new RecursiveDirectoryIterator($path); 
    $filterItr = new Filter($dirItr); 
    $objects = new RecursiveIteratorIterator($filterItr, RecursiveIteratorIterator::SELF_FIRST); 

    $objects->setMaxDepth(self::MAX_DEPTH); 

    echo '<pre>'; 
    foreach ($objects as $splFileInfo) { 
     echo $splFileInfo; 
     echo "\n"; 
    } 

我不打算進入形成一些特定結構的分級陣列中的你,但也許此相關的問題進一步幫助您瞭解RecursiveIteratorIteratorRecursiveIterator 之間的區別How does RecursiveIteratorIterator work in PHP?