Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Recursive regex filter iterator iterator

Tags:

php

I'm simply trying to loop through all the files in a directory, recursively, filtering to only those that match a pattern.

Turns out RegexIterator gives you the regex match object, but I want the SplInfo object.

So here's what I've got:

class RegexFilterIterator extends RecursiveFilterIterator {

    private $pattern;

    public function __construct(RecursiveIterator $iterator, $pattern) {
        parent::__construct($iterator);
        $this->pattern = $pattern;
    }


    public function accept() {
        return preg_match($this->pattern, $this->current()->getFilename()) > 0;
    }
}

$dir = new RecursiveDirectoryIterator($argv[1]);
$regex = new RegexFilterIterator($dir, '/\.php5?\z/i');
$it = new RecursiveIteratorIterator($regex);



foreach($it as $foo) {
   echo $foo->getPathname().PHP_EOL;
}

But this doesn't appear to be recursive.

I believe that's because \RegexFilterIterator::accept is actually being fed the directories too and I'm rejecting them because they don't end with .php.

Easy fix, right? Just amend it slightly:

public function accept() {
    return $this->current()->isDir() || preg_match($this->pattern, $this->current()->getFilename()) > 0;
}

And now it's crashing:

PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function RegexFilterIterator::__construct(), 1 passed and exactly 2 expected in bleep

Which doesn't make any sense to me. Why is trying to construct more instances of RegexFilterIterator on its own, and how is it messing it up??

I'd put the RegexFilterIterator after the RecursiveIteratorIterator, but then it yells at me:

PHP Fatal error: Uncaught TypeError: Argument 1 passed to RegexFilterIterator::__construct() must implement interface RecursiveIterator, instance of RecursiveIteratorIterator given

So... I don't know how you're supposed to use these classes.

How can I recurse all the files in a dir, and filter them with a simple regex, giving me back a generator/iterable that produces SplInfo objects?

like image 676
mpen Avatar asked Dec 06 '25 02:12

mpen


1 Answers

Found this buried in the comments on php.net, posted by "sun", and improved it a bit:

$directory = new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS);
$filter = new \RecursiveCallbackFilterIterator($directory, function ($current, $key, $iterator) {
    return $current->isDir() || preg_match('/\.php5?\z/',$current->getPathname()) > 0;
});
$iterator = new \RecursiveIteratorIterator($filter);

foreach($iterator as $file) {
   echo $file->getPathname().PHP_EOL;
}

The RecursiveCallbackFilterIterator seems to be a bit easier to work with, rather than extending RecursiveFilterIterator. There's also a FilesystemIterator::SKIP_DOTS flag which is handy.

like image 64
mpen Avatar answered Dec 08 '25 14:12

mpen