在遍历文件系统时使用 SPL 迭代器有什么优势


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

我一直在做相当多的研究,得出的结论是,我宁愿用愚蠢的旧scandirforeach来实现所有内容,而不是走迭代器的方式。

基本上,我需要一种方法来获取目录的内容 - 可选排序、可选递归和可选按文件名过滤。哪些 IMO 是您期望从任何有点复杂的文件系统遍历器中获得的最基本功能。

事实证明,RecursiveDirectoryIteratorFilesystemIterator都不支持排序过滤。必须将它们包装在一个扩展ArrayObject的类中,以实现排序 - 或FilterIterator过滤。因此,要实现这两个目标,您必须编写两个类,将所有内容包装在无数的关卡中,代码最终看起来古怪且过于复杂。

是否错过了该方法的某些内容,或者我应该在简单愚蠢的if/else/foreach代码中划伤进度并重写 20+ 行中的所有内容?

SPL中找到的迭代器并不都是"准备就绪的"。它们是基本块,可用于创建您想要的任何内容。该FileSystemIterator可能具有一些用于过滤的基本功能,但您想自己创建更多功能,并且这样做很容易。

使用FilesystemIterator等迭代器的好处是,您将遍历逻辑与筛选器逻辑分离,将排序逻辑与业务逻辑分离。

假设您有以下条件:

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

稍后,您决定仅过滤 MP3 文件:

$dir = opendir('.');
while (($file = readdir($dir)) !== false) {
  if (preg_match('|'.mp3$|i', $file)) {
   // business logic
  }
}
但是,过滤MP3和JPG文件,或小于

5MB且仅一周前的MP3文件,以及超过2MB的JPG文件,以及多个目录或递归目录等呢?你的"foreach/while"循环变成了一场噩梦,即使它开始相当不错。

通过将遍历逻辑与业务逻辑分离,意味着更易于维护、测试甚至重用:

$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
}
很容易

想象我们如何将迭代器逻辑"构建"到更复杂的示例中,并且我们可以将RegexIterator之类的东西重用于文件名以外的其他事情。测试起来也容易得多,因为我们只需要检查regexFilterIterator是否正确过滤正则表达式,就是这样。

排序等也可以根据你喜欢的任何内容添加,但仍然:你的业务逻辑没有变化,并且仍然与所有其他逻辑分离。

看看Symfony2的Finder组件:它使用大量的迭代器来过滤和排序项目。