Comment RecursiveIteratorIterator travail en PHP?
Comment RecursiveIteratorIterator
travail?
Le manuel PHP n'a rien de très documenté, ni expliqué. Quelle est la différence entre IteratorIterator
et RecursiveIteratorIterator
?
- il y a un exemple dans le php.net/manual/en/recursiveiteratoriterator.construct.php et il y a aussi une Introduction au php.net/manual/en/class.iteratoriterator.php - pouvez-vous s'il vous plaît signaler ce qu'est exactement vous avez du mal à comprendre. Ce que doit contenir dans le Manuel afin de le rendre plus facile à comprendre?
- Si vous vous demandez comment
RecursiveIteratorIterator
travaux, avez-vous déjà compris commentIteratorIterator
œuvres? Je veux dire, c'est fondamentalement la même, seule l'interface qui est consommée par les deux est différent. Et êtes-vous plus intéressé dans certains exemples ou voulez-vous voir la diff de la sous-tendent le code C de la mise en œuvre? - je n'étais pas sûr de savoir comment ne seule boucle foreach peut parcourir tous les éléments dans l'arborescence
- je suis maintenant en train d'étudier tous les construit dans les interfaces ainsi que les spl de l'interface et de l'itérateur implementetion.J'étais curieux de savoir comment ça fonctionne dans le fond avec forach boucle avec quelques exemples.
Vous devez vous connecter pour publier un commentaire.
RecursiveIteratorIterator
est un bétonIterator
la mise en œuvre de l'arbre transversal. Il permet au programmeur de parcourir un conteneur d'objet qui implémente l'RecursiveIterator
interface, voir Itérateur dans Wikipedia pour les principes généraux, les types, de la sémantique et des modèles de itérateurs.Dans la différence de
IteratorIterator
qui est un bétonIterator
la mise en œuvre de l'objet de traversée de l'ordre linéaire en (et par défaut, en acceptant tout type deTraversable
dans son constructeur), leRecursiveIteratorIterator
permet de boucler sur tous les nœuds dans un commandé arbre d'objets et de son constructeur prend unRecursiveIterator
.En bref:
RecursiveIteratorIterator
permet de vous faire une boucle sur un arbre,IteratorIterator
permet de vous faire une boucle sur une liste. Je montre que, avec des exemples de code ci-dessous bientôt.Techniquement cela fonctionne par rupture de la linéarité en parcourant tout les nœuds enfants (le cas échéant). Cela est possible parce que, par définition, tous les enfants d'un nœud sont encore une
RecursiveIterator
. Le toplevelIterator
puis interne des piles différentesRecursiveIterator
s par leur profondeur et conserve un pointeur vers le courant actif sousIterator
pour la traversée.Cela permet de visiter tous les nœuds d'un arbre.
Les principes sous-jacents sont les mêmes qu'avec
IteratorIterator
: Une interface spécifie le type d'itération de base et la classe iterator est la mise en œuvre de ces sémantique. Comparer avec les exemples ci-dessous, pour linéaire en boucle avecforeach
vous normalement ne pense pas que sur les détails de mise en œuvre, sauf si vous avez besoin de définir un nouveauIterator
(par exemple, lorsque certains type de béton lui-même ne pas mettre en œuvreTraversable
).Récursive de la traversée - à moins que vous n'utilisez pas un pré-définis
Traversal
qui a déjà récursive de la traversée à l'itération - vous normalement besoin pour instancier l'existantRecursiveIteratorIterator
itération ou même d'écrire un appel récursif à la traversée de l'itération est unTraversable
votre propre à ce type de traversée de l'itération avecforeach
.Différences techniques en bref:
IteratorIterator
prend toutTraversable
linéaire transversal,RecursiveIteratorIterator
besoins plus spécifiques,RecursiveIterator
faire une boucle sur un arbre.IteratorIterator
expose ses principalesIterator
viagetInnerIerator()
,RecursiveIteratorIterator
fournit le courant actif sous-Iterator
uniquement via cette méthode.IteratorIterator
est totalement pas au courant de quoi que ce soit comme parent ou enfants,RecursiveIteratorIterator
sait comment l'obtenir et traverse les enfants.IteratorIterator
n'a pas besoin d'une pile de itérateurs,RecursiveIteratorIterator
a une pile et sait l'actif sous-itérateur.IteratorIterator
a son ordre en raison de la linéarité et la pas le choix,RecursiveIteratorIterator
a un choix pour plus transversal et doit décider, pour chaque nœud (décidé par mode parRecursiveIteratorIterator
).RecursiveIteratorIterator
a plus de méthodesIteratorIterator
.Pour résumer:
RecursiveIterator
est un type concret de l'itération (en boucle sur un arbre) qui travaille sur son propre itérateurs, à savoirRecursiveIterator
. C'est le même principe qu'avecIteratorIerator
, mais le type d'itération est différent (ordre linéaire).Idéalement, vous pouvez créer votre propre jeu, trop. La seule chose nécessaire est que votre itérateur implémente
Traversable
qui est possible viaIterator
ouIteratorAggregate
. Ensuite, vous pouvez l'utiliser avecforeach
. Par exemple une sorte de ternaire de l'arbre transversal récursive itération de l'objet avec la fonction d'itération de l'interface de l'objet conteneur(s).Passons en revue avec quelques exemples de la vie réelle qui ne sont pas abstraites. Entre les interfaces, béton les itérateurs, d'un conteneur d'objets d'itération et de la sémantique, ce n'est peut être pas une mauvais idée.
Prendre un listing de répertoire comme un exemple. Considérez que vous avez obtenu le fichier suivant et de l'arborescence des répertoires sur le disque:
Tandis qu'un itérateur, ordre linéaire viens de parcourir au cours de la racine de dossiers et de fichiers (une seule liste de répertoire), le récursive itérateur parcourt les sous-dossiers ainsi et la liste de tous les dossiers et fichiers (une liste de répertoire avec des annonces de ses sous-répertoires):
Vous pouvez facilement les comparer avec
IteratorIterator
qui n'a pas de récursivité pour parcourir l'arborescence des répertoires. Et leRecursiveIteratorIterator
qui peut parcourir dans l'arbre que les Récursive liste indique.Au premier abord un exemple très simple avec un
DirectoryIterator
qui implémenteTraversable
qui permetforeach
à itérer dessus:L'exemplaire de sortie pour la structure de répertoire ci-dessus est alors:
Comme vous le voyez ce n'est pas encore à l'aide de
IteratorIterator
ouRecursiveIteratorIterator
. Au lieu de cela il tout simplement à l'aide deforeach
qui fonctionne sur leTraversable
interface.Comme
foreach
par défaut ne connaît que le type d'itération nommée ordre linéaire, on peut spécifier le type d'itération explicitement. À première vue, il peut sembler trop verbeux, mais pour les besoins de la démonstration (et de faire la différence avecRecursiveIteratorIterator
plus visible plus tard), permet de spécifier le type linéaire de l'itération de spécifier explicitement l'IteratorIterator
type d'itération pour l'inscription à l'annuaire:Cet exemple est près de identique à la première, la différence est que
$files
est maintenant unIteratorIterator
type d'itération pourTraversable
$dir
:Comme d'habitude, la loi de l'itération est effectuée par le
foreach
:La sortie est exactement le même. Donc ce qui est différent? Différente est l'objet utilisé dans le
foreach
. Dans le premier exemple, c'est unDirectoryIterator
dans le deuxième exemple, c'est leIteratorIterator
. Cela montre la flexibilité des itérateurs ont: Vous pouvez remplacer les uns avec les autres, le code à l'intérieurforeach
il suffit de continuer à fonctionner comme prévu.Permet de commencer à obtenir toute la liste, y compris les sous-répertoires.
Maintenant que nous avons spécifié le type de l'itération, nous allons envisager de le changer pour un autre type d'itération.
Nous savons que nous avons besoin de parcourir toute l'arborescence maintenant, non seulement le premier niveau. Pour le fonctionnement avec un simple
foreach
nous avons besoin d'un autre type d'itérateur:RecursiveIteratorIterator
. Et que l'on ne peut itérer sur conteneur des objets qui ont leRecursiveIterator
de l'interface.L'interface est un contrat. Toute classe implémentant il peut être utilisé conjointement avec le
RecursiveIteratorIterator
. Un exemple d'une telle classe est laRecursiveDirectoryIterator
, qui est quelque chose comme la variante récursive deDirectoryIterator
.Permet de voir un premier exemple de code avant d'écrire une phrase avec le mot:
Ce troisième exemple est près de identique à la première, mais elle crée une certaine différente de sortie:
Ok, pas si différent, le nom de fichier contient le chemin d'accès à l'avant, mais le reste ressemble ainsi.
Comme le montre l'exemple, même l'objet d'annuaire déjà imlements la
RecursiveIterator
de l'interface, ce n'est pas encore assez pour faireforeach
traverse l'ensemble de l'arborescence du répertoire. C'est là que leRecursiveIteratorIterator
entre en action. Exemple 4 montre comment:À l'aide de la
RecursiveIteratorIterator
au lieu de simplement la précédente$dir
objet de faireforeach
de parcourir plus de tous les fichiers et répertoires de manière récursive. Cette énumère ensuite tous les fichiers, comme le type de l'objet d'itération a été spécifié maintenant:Ce qui devrait déjà démontrer la différence entre les plats et l'arbre transversal. Le
RecursiveIteratorIterator
est capable de traverser toute la structure en arbre comme une liste d'éléments. Parce qu'il n'y est plus de l'information (comme le niveau de l'itération prend actuellement en place), il est possible d'accéder à l'itérateur de l'objet lors de l'itération sur elle, et par exemple en retrait de la sortie:Et de sortie de Exemple 5:
Sûr que ce n'est pas de gagner un concours de beauté, mais il montre que, avec le récursive itérateur, il n'y a plus d'informations disponibles que juste l'ordre linéaire de clé et valeur. Même
foreach
ne peut qu'exprimer ce genre de linéarité, l'accès à l'itérateur en lui-même permet d'obtenir plus d'informations.Similaire à la méta-information, il existe également différentes manières sur la façon de parcourir l'arbre et, par conséquent, de l'ordre de la sortie. C'est le Mode de la
RecursiveIteratorIterator
et il peut être réglé avec le constructeur.L'exemple suivant, on va dire le
RecursiveDirectoryIterator
pour supprimer le point d'entrées (.
et..
) que nous n'avons pas besoin d'eux. Mais aussi la récursivité mode sera modifiée afin de prendre le parent de l'élément (le sous-répertoire) premier (SELF_FIRST
), avant que les enfants (les fichiers et les sous-sous-dossiers dans le sous-répertoire):La sortie montre maintenant le sous-répertoire entrées correctement indiqué, si vous comparez avec le résultat précédent ceux qui n'étaient pas là:
La récursivité mode de contrôle donc quoi et quand un brach ou feuille de l'arbre est renvoyé, pour le répertoire exemple:
LEAVES_ONLY
(par défaut): Seuls les fichiers de la liste, pas de répertoires.SELF_FIRST
(ci-dessus): Liste de répertoire et les fichiers là.CHILD_FIRST
(w/o exemple): Liste les fichiers dans le répertoire en premier, puis le répertoire.Sortie de Exemple 5 avec les deux autres modes:
Lorsque vous comparez cela avec la traversée standard, toutes ces choses ne sont pas disponibles. Récursive itération est donc un peu plus complexe quand vous en avez besoin pour envelopper votre tête autour de lui, cependant il est facile à utiliser car il se comporte comme un itérateur, vous la mettez dans un
foreach
et fait.Je pense qu'ils sont assez d'exemples pour une réponse. Vous trouverez l'intégralité du code source, ainsi qu'un exemple d'afficher de jolies ascii-arbres dans ce gist: https://gist.github.com/3599532
Exemple 5 démontré qu'il existe des méta-informations sur l'itérateur de l'état disponible. Toutefois, cela a été délibérément démontré dans la
foreach
itération. Dans la vraie vie, naturellement, cela appartient à l'intérieur de laRecursiveIterator
.Meilleur exemple en est la
RecursiveTreeIterator
, il prend soin de l'indentation, la préfixation et ainsi de suite. Voir le fragment de code suivant:La
RecursiveTreeIterator
est destiné à travailler ligne par ligne, la sortie est assez simple, avec un petit problème:Lorsqu'utilisé en combinaison avec un
RecursiveDirectoryIterator
il affiche tout le chemin et de ne pas simplement le nom de fichier. Le reste semble bon. C'est parce que les noms de fichiers sont générés parSplFileInfo
. Celles-ci doivent être affichés sous le nom de base à la place. Le résultat souhaité est le suivant:Créer un décorateur classe qui peut être utilisée avec
RecursiveTreeIterator
au lieu de laRecursiveDirectoryIterator
. Il doit fournir le nom de base de l'actuelSplFileInfo
au lieu du chemin. Le dernier fragment de code pourrait alors ressembler à ceci:Ces fragments dont
$unicodeTreePrefix
font partie de l'essentiel dans Annexe: Do It Yourself: Faites leRecursiveTreeIterator
Travailler ligne par Ligne..IteratorIterator
, sa raison d'être.RecursiveIteratorIterator
fonctionne (il sait comment appelergetChildren()
, par exemple).SELF_FIRST
, les autres modes sont disponibles et surtout le nom de la mode par défaut (re. "points de base" mentionné plus haut).RecursiveIteratorIterator
parce que c'est en commun avec d'autres types, mais je n'ai donner quelques infos techniques de la façon dont il fonctionne réellement. Les exemples, je pense que montrent bien les différences: le type d'itération est la principale différence entre les deux. Aucune idée de si vous achetez le type d'itération, vous pièce un peu différemment, mais à mon humble avis, pas facile avec la sémantique des types d'itération ont.De comprendre la différence entre ces deux itérateurs, on doit d'abord comprendre un peu plus sur les conventions de nommage utilisées et ce que nous entendons par "récursive" les itérateurs.
Récursives et non récursives itérateurs
PHP non"récursive" les itérateurs, comme
ArrayIterator
etFilesystemIterator
. Il y a aussi "récursive" itérateurs comme leRecursiveArrayIterator
etRecursiveDirectoryIterator
. Ces derniers ont des méthodes leur permettant d'être forées, les anciens n'en ont pas.Lorsque des instances de ces itérateurs sont bouclés sur eux-mêmes, même le récursive, les valeurs viennent uniquement de le "haut" niveau, même si une boucle sur un tableau imbriqué ou un répertoire avec ses sous-répertoires.
Le récursive itérateurs mettre en œuvre récursive comportement (via
hasChildren()
,getChildren()
), mais ne pas exploiter il.Il pourrait être préférable de considérer le récursive itérateurs comme "recursible" les itérateurs, ils ont le capacité être répétées de manière récursive, mais simplement une itération sur une instance de l'une de ces classes ne sera pas le faire. Pour exploiter le comportement récursif, continuez à lire.
RecursiveIteratorIterator
C'est là que le
RecursiveIteratorIterator
vient de jouer. Il a la connaissance de la façon d'appeler les "recursible" les itérateurs de manière à descendre dans la structure dans un état normal, plat, boucle. Il met l'récursive comportement dans l'action. Il est essentiellement le fait de marcher sur chacune des valeurs dans l'itérateur, regarder pour voir si il y a des "enfants" de manière récursive ou non, et de d'entrer dans et hors de ces collections des enfants. Vous vous en tenez une instance deRecursiveIteratorIterator
dans un foreach, et il plonge dans la structure, de sorte que vous n'avez pas à.Si le
RecursiveIteratorIterator
n'a pas été utilisé, vous devez écrire votre propre récursive boucles d'exploiter le comportement récursif, de la vérification des "recursible" itérateur esthasChildren()
et à l'aide degetChildren()
.Donc, c'est un bref aperçu de
RecursiveIteratorIterator
, comment est-il différent deIteratorIterator
? Eh bien, vous êtes essentiellement en posant le même type de question que Quelle est la différence entre un chaton et un arbre? Tout simplement parce que les deux apparaissent dans la même encyclopédie (ou manuel, pour les itérateurs) ne signifie pas que vous devrait se confondre entre les deux.IteratorIterator
Le travail de la
IteratorIterator
est de prendre toutes lesTraversable
objet, et l'envelopper tel qu'il répond à laIterator
interface. A utiliser pour ce est pour ensuite être en mesure d'appliquer itérateur spécifiques sur le comportement des non-objet itérateur.Pour donner un exemple concret, le
DatePeriod
classe estTraversable
mais pas unIterator
. En tant que tel, nous pouvons en boucle sur ses valeurs avecforeach()
mais ne peut pas faire d'autres choses que nous avons l'habitude de le feriez avec un itérateur, telles que le filtrage.TÂCHE: Boucle sur les lundis, mercredis et vendredis de les quatre prochaines semaines.
Oui, c'est trivial par
foreach
-ing sur leDatePeriod
et à l'aide d'unif()
dans la boucle; mais ce n'est pas le point de cet exemple!L'extrait ci-dessus ne fonctionnera pas parce que les
CallbackFilterIterator
attend une instance d'une classe qui implémente l'Iterator
interface, quiDatePeriod
ne le fait pas. Cependant, depuis qu'il estTraversable
on peut facilement satisfaire à cette exigence en utilisantIteratorIterator
.Comme vous pouvez le voir, ce qui a rien que ce soit à voir avec une itération sur itérateur classes, ni la récursivité, et c'est là que réside la différence entre
IteratorIterator
etRecursiveIteratorIterator
.Sommaire
RecursiveIteraratorIterator
est pour itérer sur unRecursiveIterator
("recursible" itérateur), en exploitant le comportement récursif qui est disponible.IteratorIterator
est pour l'application deIterator
comportement de non-itérateur,Traversable
objets.IteratorIterator
juste le type standard de l'ordre linéaire de la traversée pourTraversable
objets? Ceux qui pourraient être utilisées sans justeforeach
que c'est? Et encore plus loin, n'est-ce pas unRecursiveIterator
toujours unTraversable
et, par conséquent, non seulementIteratorIterator
mais aussiRecursiveIteratorIterator
toujours "pour l'application deIterator
comportement de non-itérateur, Traversable objets"? (Je voudrais maintenant direforeach
applique le type d'itération par l'itérateur sur l'objet conteneur des objets qui implémentent un itérateur de type interface de sorte que ces sont itérateur-conteneur-objets, toujoursTraversable
)IteratorIterator
est une classe qui est tout au sujet de emballageTraversable
objets dans unIterator
. Rien de plus. Vous semblez appliquer le terme plus général.Recursive
dansRecursiveIterator
implique comportement, tandis que la plus convenable nom aurait été celui qui décrit la capacité, commeRecursibleIterator
.RecursiveDirectoryIterator il affiche tout le chemin et de ne pas simplement le nom de fichier. Le reste semble bon. C'est parce que les noms de fichiers sont générés par SplFileInfo. Celles-ci doivent être affichés sous le nom de base à la place. Le résultat souhaité est le suivant:
de sortie:
Lorsqu'il est utilisé avec
iterator_to_array()
,RecursiveIteratorIterator
sera récursive de parcourir le tableau pour trouver toutes les valeurs. Ce qui signifie qu'il va s'aplatir le tableau d'origine.IteratorIterator
gardera la structure hiérarchique d'origine.Cet exemple va vous montrer clairement la différence:
new IteratorIterator(new ArrayIterator($array))
est équivalent ànew ArrayIterator($array)
, qui est, à l'extérieurIteratorIterator
est de ne rien faire. En outre, l'aplatissement de la sortie n'a rien à voir aveciterator_to_array
– il convertit simplement l'itérateur à un tableau. L'aplatissement est une propriété de la façonRecursiveArrayIterator
promenades intérieures itérateur.