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

时间:2016-02-28 08:09:35

标签: php iterator php-5.5 spl

我有以下非常简单的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)

1 个答案:

答案 0 :(得分:1)

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

您看到两行,因为$item值适用于"。"和" .."项目,并且尝试使用SKIP_DOTS是正确的,因为您很可能希望跳过这些项目。

然而,RecursiveIteratorIterator的默认行为是仅迭代" leaf"项目(即不包含更多项目的项目)而非一切,有效地跳过目录。

所以,你需要告诉RecursiveIteratorIterator使用不同的模式,而不是默认的"只留下" mode:" self first"或者"孩子先"。

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

回到原始代码,您可以通过回显$item->getPathname()(或简单地回显$item在这里工作)来查看正在进行的操作。那将显示"点目录"你需要跳过。