【问题标题】:Creating new Iterator from the results of another Iterator从另一个迭代器的结果创建新的迭代器
【发布时间】:2010-10-09 04:10:48
【问题描述】:

我正在尝试在 PHP 5 中有效地使用迭代器,但网络上没有很多像样的示例,事实证明这有点困难。

我正在尝试遍历一个目录,并读取其中的所有 (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()) 来实现目标。

简而言之,我试图确定我可以使用(或扩展)哪个迭代器来让它传递对象的一维数组(?),并让它将结果数组组合成一个主数组并返回。

我意识到还有其他几种方法可以解决这个问题,比如:

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

但这违背了使用迭代器的目的,而且作为解决方案也不是很优雅。

无论如何,我希望我已经解释得足够好。感谢您阅读本文,并提前回答:)

【问题讨论】:

    标签: php filter iterator


    【解决方案1】:

    我曾经做过类似的事情。我相信source is right here 很容易理解。如果您有任何问题,请告诉我。

    主要思想是扩展SplFileInfo,然后使用RecursiveIteratorIterator::setInfoClass($className); 来获取有关源代码的信息。一个只解析 PHP 文件的过滤器可能会很好,尽管我当时决定在主循环中通过扩展来过滤它们。

    【讨论】:

      【解决方案2】:

      是的,我最终设法解决了这个问题。我必须使用递归迭代器,因为输入迭代器本质上是生成子结果,并且我扩展了 IteratorIterator,它已经具有循环遍历迭代器的功能。

      无论如何,这是一个代码示例,以防万一这对其他人有帮助。这假设您已经传入了一个 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
                  )
              );
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-07-24
        • 2018-07-14
        • 2018-05-20
        • 1970-01-01
        • 2021-10-15
        • 1970-01-01
        • 2021-02-01
        • 1970-01-01
        • 2013-06-17
        相关资源
        最近更新 更多