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

标签 php filter iterator

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

我正在尝试遍历一个目录,并读取其中的所有 (php) 文件以搜索已定义的类。然后我想要做的是返回一个关联数组,其中类名作为键,文件路径作为值。

通过使用 RecursiveDirectoryIterator(),我可以递归遍历目录。 通过将其传递给 RecursiveIteratorIterator,我可以将目录的内容检索为一维迭代器。 然后对此使用过滤器,我可以过滤掉所有目录和非 php 文件,这些文件只会留下我想要考虑的文件。

我现在想要做的是能够将这个迭代器传递给另一个迭代器(不确定哪个合适),这样当它遍历每个条目时,它可以检索一个数组,它需要组合成一个 master数组。

解释起来有点复杂,所以这里有一个代码示例:

// $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);
    }
}

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

无论如何,我希望我已经解释得够清楚了。感谢您阅读到这里,并提前回答您的问题 :)

最佳答案

是的,我最终设法解决了这个问题。我必须使用递归迭代器,因为输入迭代器本质上是生成子结果,并且我扩展了 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
            )
        );
    }
}

关于php - 从另一个迭代器的结果创建新的迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/575106/

相关文章:

php - 问号冒号运算符的含义

ios - 如何去除图像的噪点?

javascript - 如何将占位符设置为表格过滤器?

C++:使用 fstream、映射和输出

php - 从 MySQL 数据库获取数据到 HTML 下拉列表

php - .htaccess 在开发、暂存和生产之间

javascript - 上传文件扩展名过滤器选项不起作用?

java - Java 中迭代器因 1 次混淆而关闭

C循环双链表: traverses fwd/rev for end node gives different pointer address

php - PDO 绑定(bind)未知数量的参数?