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( )) 来实现目标。

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

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

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

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

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

4

2 回答 2

1

是的,我最终设法解决了这个问题。我不得不使用递归迭代器,因为输入迭代器本质上是生成子结果,并且我扩展了 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
            )
        );
    }
}
于 2009-02-25T23:21:22.533 回答
0

我曾经做过类似的事情。来源就在这里,我相信很容易理解。如果您有任何问题,请告诉我。

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

于 2009-02-23T08:59:19.690 回答