2009-02-22 42 views
3

我試圖在PHP 5中有效地使用Iterators,並且在網絡上沒有很多體面的示例,但它證明有點困難。從另一個Iterator的結果創建新的Iterator

我想循環一個目錄,並讀取所有(PHP)文件內搜索定義的類。然後我想要做的是有一個關聯數組返回,類名稱爲鍵,文件路徑爲值。

通過使用RecursiveDirectoryIterator(),我可以遍歷目錄。 通過將此傳遞給RecursiveIteratorIterator,我可以將該目錄的內容作爲單維迭代器進行檢索。 然後通過使用這個過濾器,我可以過濾掉所有的目錄和非php文件,這些文件只會留下我想要考慮的文件。

我現在想要做的就是能夠將這個迭代器傳遞到另一個迭代器(不知道哪個是合適的),這樣當它遍歷每個條目時,它可以檢索一個數組,它需要組合成一個數組主陣列。

這是一個有點複雜的解釋,所以這裏是一個代碼示例:

// $php_files now represents an array of SplFileInfo objects representing files under $dir that match our criteria 
$php_files = new PhpFileFilter(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir))); 

class ClassDetector extends FilterIterator { 
    public function accept() { 
     $file = $this->current(); // get the current item, which will be an SplFileInfo object 

     // Match all the classes contained within this file 
     if (preg_match($regex, $file->getContents(), $match)) { 
      // Return an assoc array of all the classes matched, the class name as key and the filepath as value 
      return array(
       'class1' => $file->getFilename(), 
       'class2' => $file->getFilename(), 
       'class3' => $file->getFilename(), 
      ); 
     } 
    } 
} 

foreach (new ClassDetector($php_files) as $class => $file) { 
    print "{$class} => {$file}\n"; 
} 

// Expected output: 
// class1 => /foo.php 
// class2 => /foo.php 
// class3 => /foo.php 
// class4 => /bar.php 
// class5 => /bar.php 
// ... etc ... 

正如你從這個例子可以看到,我種劫持FilterIterator的accept()方法,這是完全不正確用法我知道 - 但我只用它作爲示例來演示我只想調用一個函數,並且它返回一個數組,並將其合併到一個主數組中。

此刻我想我將不得不使用RecursionIterators之一,因爲這似乎是他們做的,但我不喜歡使用兩種不同方法(hasChildren( )和getChildren())來實現目標。

簡而言之,我試圖確定哪些Iterator可以使用(或擴展)讓它通過對象的一維數組(?),並讓它將結果數組組合到一個主一個並返回。

我知道身邊有這幾款其他的方式,ALA是這樣的:

$master = array(); 
foreach($php_files as $file) { 
    if (preg_match($regex, $file->getContents(), $match)) { 
     // create $match_results 
     $master = array_merge($master, $match_results); 
    } 
} 

但這違背了使用迭代器的目的,這是不是很優雅無論是作爲一個解決方案。

無論如何,我希望我已經解釋得很好。感謝您閱讀這一點,並提前爲您解答:)

回答

1

沒錯,我終於設法讓我的腦袋周圍。我不得不使用遞歸迭代器,因爲輸入迭代器本質上是生成子結果,並且我擴展了IteratorIterator,它已經具有循環遍歷Iterator的功能。

無論如何,這裏是一個代碼示例,以防萬一這有助於其他人。這假設你已經傳入了一個SplFileInfo對象數組(無論如何都是DirectoryIterator的結果)。

class 
    ClassMatcher 
extends 
    IteratorIterator 
implements 
    RecursiveIterator 
{ 

    protected $matches; 

    public function hasChildren() { 
     return preg_match_all(
      '#class (\w+)\b#ism', 
      file_get_contents($this->current()->getPathname()), 
      $this->matches 
     ); 
    } 

    public function getChildren() { 
     $classes = $this->matches[1]; 

     return new RecursiveArrayIterator(
      array_combine(
       $classes,              // class name as key 
       array_fill(0, count($classes), $this->current()->getPathname()) // file path as value 
      ) 
     ); 
    } 
} 
0

我曾經做過類似的事情。 source is right here,我相信很容易理解。如果您有任何問題,請告訴我。

主要的想法是延長SplFileInfo然後用RecursiveIteratorIterator :: setInfoClass($的className);爲了獲得關於源代碼的信息。一個只分析PHP文件的過濾器可能很好,但我決定在主循環中通過擴展來過濾它們。