2016-02-28 3 views
3

je le suit très simple code RecursiveDirectoryIterator:RecursiveDirectoryIterator en PHP, obtenir chaque répertoire deux fois dans 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"; 

mais produit la sortie suivante:

/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 

Au moment où je quitte la boucle I compté chaque répertoire deux fois (j'obtiens la liste double et $ countd est 12, au lieu de 6).

Pourquoi se comporte-t-il de cette façon? Comment l'éviter?

J'ai essayé d'utiliser RecursiveDirectoryIterator::SKIP_DOTS comme indicateur, mais il ignore tous les répertoires (mais compte les fichiers).

(PHP 5,5)

+0

Personnellement, je ne sais pas comment le réparer au cœur de la classe, mais pour le contourner (si vous êtes pressé) est sortie dans un tableau puis 'array_unique()' – Rasclatt

+0

Yup, et je peux Pensez à d'autres solutions rapides, mais surtout, je voudrais comprendre ce comportement. Merci quand même! – yivi

+0

Oui, je vous entends. J'ai rencontré des comportements bizarres comme celui-ci avec les itérateurs et je les corrige rapidement, donc je suis aussi intéressé à corriger ce comportement particulier au niveau de la classe. – Rasclatt

Répondre

1

TL; DR utilisation RecursiveIteratorIterator::SELF_FIRST comme mode itération, ainsi que le drapeau RecursiveDirectoryIterator::SKIP_DOTS.


Vous voyez deux lignes parce que les valeurs sont $item pour le « » et ".." articles, et ont eu raison d'essayer d'utiliser SKIP_DOTS comme vous le souhaitez probablement de passer ces éléments. Toutefois, le comportement par défaut du RecursiveIteratorIterator consiste à parcourir uniquement les éléments "feuille" (c'est-à-dire les éléments qui ne contiennent pas plus d'éléments) plutôt que tout, en ignorant les répertoires. Donc, vous devez dire à RecursiveIteratorIterator d'utiliser un mode différent, autre que le mode par défaut "leaves only": un de "self first" ou "child first".

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

Retour à votre code d'origine, vous pouvez voir ce qui se passe en écho $item->getPathname() (ou écho $item ne fonctionnerait tout simplement ici). Cela vous montrerait les "répertoires de points" que vous devez ignorer.