首页 文章

从另一个迭代器的结果创建新的迭代器

提问于
浏览
3

我试图在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( ))实现目标 .

简而言之,我正在尝试确定哪个Iterator可以使用(或扩展)以使其通过对象的一维数组(?),并让它将结果数组合成一个主数组并返回 .

我意识到还有其他几种方法,例如:

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

但这违背了使用迭代器的目的,并且它作为一种解决方案并不是很优雅 .

无论如何,我希望我已经解释得那么好了 . 感谢您阅读这篇文章,并提前获得答案:)

2 回答

  • 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文件的过滤器可能不错,但我当时决定在主循环中通过扩展来过滤它们 .

相关问题