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


RecursiveDirectoryIterator in PHP, getting each directory twice in foreach

我有以下非常简单的递归目录迭代器代码:

$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的默认行为是仅迭代"叶"项(即不包含更多项的项目)而不是所有项,从而有效地跳过目录。

因此,您需要告诉RecursiveIteratorIterator使用不同的模式,而不是默认的"仅离开"模式:"自我优先"或"孩子优先"模式之一。

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

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