PHP 中的 RecursiveDirectoryIterator,在 foreach 中获取每个目录两次

RecursiveDirectoryIterator in PHP, getting each directory twice in foreach

我有以下非常简单的 RecursiveDirectoryIterator 代码:

$dir = new RecursiveDirectoryIterator('/Users/yivi/test/',  RecursiveDirectoryIterator::KEY_AS_PATHNAME);

$iter = new RecursiveIteratorIterator($dir);

foreach ($iter as $item) {
  if ($item->isDir()) {
      echo $item->getPath() . "\n";
      $countd ++;
  } else {
      $count++;
  }
}
echo "$count files and $count directories";

但产生以下输出:

/Users/yivi/Sites/test
/Users/yivi/Sites/test
/Users/yivi/Sites/test/01
/Users/yivi/Sites/test/01
/Users/yivi/Sites/test/02
/Users/yivi/Sites/test/02
/Users/yivi/Sites/test/03
/Users/yivi/Sites/test/03
/Users/yivi/Sites/test/03/ab
/Users/yivi/Sites/test/03/ab
/Users/yivi/Sites/test/03/cd
/Users/yivi/Sites/test/03/cd

40 files and 12 directories

当我退出循环时,我对每个目录进行了两次计数(我得到了双重列表并且 $countd 是 12,而不是 6)。

为什么会这样?如何避免?

我试过使用 RecursiveDirectoryIterator::SKIP_DOTS 作为标志,但它会跳过所有目录(但会计算文件数)。

(PHP 5.5)

TL;DR 使用 RecursiveIteratorIterator::SELF_FIRST 作为迭代模式,以及 RecursiveDirectoryIterator::SKIP_DOTS 标志。


您看到两行是因为 $item 值用于“.”。和“..”项目,尝试使用 SKIP_DOTS 是正确的,因为您很可能确实想跳过这些项目。

但是,RecursiveIteratorIterator 的默认行为是仅遍历 "leaf" 项(即不包含更多项的项)而不是所有项,从而有效地跳过目录。

因此,您需要告诉 RecursiveIteratorIterator 使用不同的模式,而不是默认的 "leaves only" 模式:"self first" 或 "child first" 之一。

$iter = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST);

回到您的原始代码,您可以通过回显 $item->getPathname()(或者简单地回显 $item 在这里工作)来查看发生了什么。这将向您显示您需要跳过的 "dot directories"。