raveren
raveren

Reputation: 18542

What is the advantage of using SPL iterators in traversing the file system?

I've been doing quite a bit of research and am coming to a conclusion I'd rather just implemented everything with dumb old scandir and foreach instead of going the iterator way.

Basically, I need a way to get contents of directories - optionally sorted, optionally recursive and optionally filtered by file name. Which IMO are the most basic functionality you would expect from any somewhat sophisticated file system traverser.

Well it turns out, neither RecursiveDirectoryIterator nor FilesystemIterator support sorting or filtering. One has to wrap them in a class that extends ArrayObject to achieve sorting - or FilterIterator for filtering. So to achieve both you have to write two classes wrapping everything in a myriad of levels and the code ends up looking outlandish and overcomplicated.

Am I missing something about the approach, or should I scratch my progress and rewrite everything in 20+ lines in simple stupid if/else/foreach code?

Upvotes: 1

Views: 202

Answers (1)

JayTaph
JayTaph

Reputation: 2916

Iterators found in the SPL aren't all "ready-to-go". They are basic blocks that can be used to create whatever you want. The FileSystemIterator has some basic functionality for filtering maybe, but you want to create more yourself, and it's quite easy to do so.

The upside of using iterators like FilesystemIterator and such, is that you detach the traversal logic from your filter logic from your sort logic from your business logic.

Say you have the following:

$dir = opendir('.');
while (($file = readdir($dir)) !== false) {
  // business logic
}

and later on, you decide to filter only MP3 files:

$dir = opendir('.');
while (($file = readdir($dir)) !== false) {
  if (preg_match('|\.mp3$|i', $file)) {
   // business logic
  }
}

But what about filtering MP3 and JPG files, or MP3 files that are less than 5MB and only a week old, and JPG files that are over 2MB, and what about multiple directories, or recursive directories etc? Your "foreach/while" loop becomes a nightmare, even though it started out quite nice.

By detaching your traversal logic from your business logic, means that it's easier to maintain, test and even reuse:

$it = new DirectoryIterator(".");      // Dir iterator
$it = new RegexIterator($it, "|\.mp3$|i");  // filter MP3's
$it = new FilesizeIterator($it, "<6MB");  // Only less than 6MB
$it = new LimitIterator($it, 0, 100);   // First 100 items only

foreach ($it as $file) {
   // extrabonus: $file is a SplFileInfo object
}

It's easy to imagine how we could "build" the iterator logic into more complex examples, and we can reuse things like a RegexIterator for other things besides filenames too. It's also much easier to test because we only need to check if regexFilterIterator correctly filters regexes, that's it.

Sorting and such can be addded as well, based on whatever you like, but still: no changes in your business logic, and still detached from all other logic.

Take a look at Symfony2's Finder component: it uses lots of iterators to filter and sort items.

Upvotes: 7

Related Questions