RecursiveIteratorIterator 在 PHP 中是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12077177/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does RecursiveIteratorIterator work in PHP?
提问by varuog
How does RecursiveIteratorIteratorwork?
如何RecursiveIteratorIterator工作?
The PHP manual has nothing much documented or explained. What is the difference between IteratorIteratorand RecursiveIteratorIterator?
PHP 手册没有太多记录或解释。IteratorIterator和 和有RecursiveIteratorIterator什么区别?
回答by hakre
RecursiveIteratorIteratoris a concrete Iteratorimplementing tree traversal. It enables a programmer to traverse a container object that implements the RecursiveIteratorinterface, see Iterator in Wikipediafor the general principles, types, semantics and patterns of iterators.
RecursiveIteratorIterator是一个具体的Iterator实现树遍历。它使程序员能够遍历实现RecursiveIterator接口的容器对象,有关迭代器的一般原则、类型、语义和模式,请参阅维基百科中的迭代器。
In difference to IteratorIteratorwhich is a concrete Iteratorimplementing object traversal in linear order (and by default accepting any kind of Traversablein its constructor), the RecursiveIteratorIteratorallows looping over all nodes in an ordered treeof objects and its constructor takes a RecursiveIterator.
与以线性顺序(并且默认情况下接受其构造函数中的任何类型)IteratorIterator的具体Iterator实现对象遍历不同的是Traversable,RecursiveIteratorIterator允许循环遍历有序对象树中的所有节点,并且其构造函数采用RecursiveIterator.
In short: RecursiveIteratorIteratorallows you to loop over a tree, IteratorIteratorallows you to loop over a list. I show that with some code examples below soon.
简而言之:RecursiveIteratorIterator允许您遍历树,IteratorIterator允许您遍历列表。我很快就会用下面的一些代码示例来说明这一点。
Technically this works by breaking out of linearity by traversing all of a nodes' children (if any). This is possible because by definition all children of a node are again a RecursiveIterator. The toplevel Iteratorthen internally stacks the different RecursiveIterators by their depth and keeps a pointer to the current active sub Iteratorfor traversal.
从技术上讲,这是通过遍历节点的所有子节点(如果有)来打破线性的。这是可能的,因为根据定义,节点的所有子节点都是 a RecursiveIterator。顶层Iterator然后在内部RecursiveIterator按深度堆叠不同的s,并保留指向当前活动子的指针以Iterator供遍历。
This allows to visit all nodes of a tree.
这允许访问树的所有节点。
The underlying principles are the same as with IteratorIterator: An interface specifies the type of iteration and the base iterator class is the implementation of these semantics. Compare with the examples below, for linear looping with foreachyou normally do not think about the implementation details much unless you need to define a new Iterator(e.g. when some concrete type itself does not implement Traversable).
底层原理与 with 相同IteratorIterator:一个接口指定迭代的类型,基迭代器类是这些语义的实现。与下面的示例相比,对于线性循环,foreach您通常不会过多考虑实现细节,除非您需要定义一个新的Iterator(例如,当某些具体类型本身没有实现时Traversable)。
For recursive traversal - unless you do not use a pre-defined Traversalthat already has recursive traversal iteration - you normally needto instantiate the existing RecursiveIteratorIteratoriteration or even write a recursive traversal iteration that is a Traversableyour own to have this type of traversal iteration with foreach.
对于递归遍历——除非你不使用Traversal已经有递归遍历迭代的预定义——你通常需要实例化现有的RecursiveIteratorIterator迭代,或者甚至编写一个Traversable你自己的递归遍历迭代来使用foreach.
Tip:You probably didn't implement the one nor the other your own, so this might be something worth to do for your practical experience of the differences they have. You find a DIY suggestion at the end of the answer.
提示:您可能没有实现一个或另一个您自己的,因此这可能是您对它们之间差异的实践经验值得做的事情。您会在答案末尾找到 DIY 建议。
Technical differences in short:
技术差异简而言之:
- While
IteratorIteratortakes anyTraversablefor linear traversal,RecursiveIteratorIteratorneeds a more specificRecursiveIteratorto loop over a tree. - Where
IteratorIteratorexposes its mainIteratorviagetInnerIerator(),RecursiveIteratorIteratorprovides the current active sub-Iteratoronly via that method. - While
IteratorIteratoris totally not aware of anything like parent or children,RecursiveIteratorIteratorknows how to get and traverse children as well. IteratorIteratordoes not need a stack of iterators,RecursiveIteratorIteratorhas such a stack and knows the active sub-iterator.- Where
IteratorIteratorhas its order due to linearity and no choice,RecursiveIteratorIteratorhas a choice for further traversal and needs to decide per each node (decided via mode perRecursiveIteratorIterator). RecursiveIteratorIteratorhas more methods thanIteratorIterator.
- 虽然
IteratorIterator采用 anyTraversable进行线性遍历,但RecursiveIteratorIterator需要更具体RecursiveIterator的循环遍历树。 - where
IteratorIterator暴露其主要IteratorviagetInnerIerator(),仅通过该方法RecursiveIteratorIterator提供当前活动的子Iterator。 - 虽然
IteratorIterator完全不知道父母或孩子之类的东西,但RecursiveIteratorIterator也知道如何获取和遍历孩子。 IteratorIterator不需要迭代器堆栈,RecursiveIteratorIterator有这样一个堆栈并且知道活动的子迭代器。IteratorIterator由于线性而没有选择的顺序在哪里,RecursiveIteratorIterator可以选择进一步遍历并且需要决定每个节点(通过mode perRecursiveIteratorIterator决定)。RecursiveIteratorIterator有更多的方法IteratorIterator。
To summarize: RecursiveIteratoris a concrete type of iteration (looping over a tree) that works on its own iterators, namely RecursiveIterator. That is the same underlying principle as with IteratorIerator, but the type of iteration is different (linear order).
总结一下:RecursiveIterator是一种具体类型的迭代(循环一棵树),它在自己的迭代器上工作,即RecursiveIterator. 这与 的基本原理相同IteratorIerator,但迭代类型不同(线性顺序)。
Ideally you can create your own set, too. The only thing necessary is that your iterator implements Traversablewhich is possible via Iteratoror IteratorAggregate. Then you can use it with foreach. For example some kind of ternary tree traversal recursive iteration object together with the according iteration interface for the container object(s).
理想情况下,您也可以创建自己的集合。唯一需要的是您的迭代器Traversable可以通过Iteratoror 实现IteratorAggregate。然后你可以将它与foreach. 例如,某种三叉树遍历递归迭代对象以及容器对象的相应迭代接口。
Let's review with some real-life examples that are not that abstract. Between interfaces, concrete iterators, container objects and iteration semantics this maybe is not a that bad idea.
让我们回顾一些不那么抽象的真实例子。在接口、具体迭代器、容器对象和迭代语义之间,这可能不是一个坏主意。
Take a directory listing as an example. Consider you have got the following file and directory tree on disk:
以目录列表为例。考虑您在磁盘上有以下文件和目录树:
While a iterator with linear order just traverse over the toplevel folder and files (a single directory listing), the recursive iterator traverses through subfolders as well and list all folders and files (a directory listing with listings of its subdirectories):
虽然具有线性顺序的迭代器只是遍历顶级文件夹和文件(单个目录列表),但递归迭代器也遍历子文件夹并列出所有文件夹和文件(一个包含其子目录列表的目录列表):
Non-Recursive Recursive
============= =========
[tree] [tree]
├ dirA ├ dirA
└ fileA │ ├ dirB
│ │ └ fileD
│ ├ fileB
│ └ fileC
└ fileA
You can easily compare this with IteratorIteratorwhich does no recursion for traversing the directory tree. And the RecursiveIteratorIteratorwhich can traverse into the tree as the Recursive listing shows.
您可以轻松地将其与IteratorIterator不使用递归遍历目录树的方式进行比较。并且RecursiveIteratorIterator可以遍历到树中,如递归列表所示。
At first a very basic example with a DirectoryIteratorthat implements Traversablewhich allows foreachto iterateover it:
首先是一个非常基本的示例,DirectoryIterator它实现Traversable了允许foreach对其进行迭代:
$path = 'tree';
$dir = new DirectoryIterator($path);
echo "[$path]\n";
foreach ($dir as $file) {
echo " ├ $file\n";
}
The exemplary output for the directory structure above then is:
上面目录结构的示例输出是:
[tree]
├ .
├ ..
├ dirA
├ fileA
As you see this is not yet using IteratorIteratoror RecursiveIteratorIterator. Instead it just just using foreachthat operates on the Traversableinterface.
如您所见,这还没有使用IteratorIteratoror RecursiveIteratorIterator。相反,它只是使用foreach在Traversable界面上操作的那个。
As foreachby default only knows the type of iteration named linear order, we might want to specify the type of iteration explicitly. At first glance it might seem too verbose, but for demonstration purposes (and to make the difference with RecursiveIteratorIteratormore visible later), lets specify the linear type of iteration explicitly specifying the IteratorIteratortype of iteration for the directory listing:
由于foreach默认情况下只知道名为线性顺序的迭代类型,我们可能希望明确指定迭代类型。乍一看,它可能看起来过于冗长,但为了演示目的(并在以后使差异RecursiveIteratorIterator更明显),让我们指定线性迭代类型,明确指定IteratorIterator目录列表的迭代类型:
$files = new IteratorIterator($dir);
echo "[$path]\n";
foreach ($files as $file) {
echo " ├ $file\n";
}
This example is nearlyidentical with the first one, the difference is that $filesis now an IteratorIteratortype of iteration for Traversable$dir:
此示例与第一个示例几乎相同,不同之处在于$files现在是 的IteratorIterator一种迭代Traversable$dir:
$files = new IteratorIterator($dir);
As usual the act of iteration is performed by the foreach:
像往常一样,迭代行为由以下人员执行foreach:
foreach ($files as $file) {
The output is exactlythe same. So what is different? Different is the object used within the foreach. In the first example it is a DirectoryIteratorin the second example it is the IteratorIterator. This shows the flexibility iterators have: You can replace them with each other, the code inside foreachjust continue to work as expected.
输出完全一样。那么有什么不同呢?不同的是在foreach. 在第一个示例中它是 aDirectoryIterator在第二个示例中它是IteratorIterator。这显示了迭代器具有的灵活性:您可以相互替换它们,其中的代码会foreach继续按预期工作。
Lets start to get the whole listing, including subdirectories.
让我们开始获取整个列表,包括子目录。
As we now have specified the type of iteration, let's consider to change it to another type of iteration.
由于我们现在已经指定了迭代类型,让我们考虑将其更改为另一种迭代类型。
We know we need to traverse the whole tree now, not only the first level. To have that work with a simple foreachwe need a different type of iterator: RecursiveIteratorIterator. And that one can only iterate over container objects that have the RecursiveIteratorinterface.
我们知道我们现在需要遍历整棵树,而不仅仅是第一层。要使用简单的方法完成这项工作,foreach我们需要一种不同类型的迭代器:RecursiveIteratorIterator. 而那个只能迭代具有RecursiveIteratorinterface 的容器对象。
The interface is a contract. Any class implementing it can be used together with the RecursiveIteratorIterator. An example of such a class is the RecursiveDirectoryIterator, which is something like the recursive variant of DirectoryIterator.
接口是一个契约。任何实现它的类都可以与RecursiveIteratorIterator. 此类的一个示例是RecursiveDirectoryIterator,它类似于 的递归变体DirectoryIterator。
Lets see a first code example before writing any other sentence with the I-word:
在使用 I 字编写任何其他句子之前,让我们先看第一个代码示例:
$dir = new RecursiveDirectoryIterator($path);
echo "[$path]\n";
foreach ($dir as $file) {
echo " ├ $file\n";
}
This third example is nearlyidentical with the first one, however it creates some different output:
第三个示例与第一个示例几乎相同,但是它创建了一些不同的输出:
[tree]
├ tree\.
├ tree\..
├ tree\dirA
├ tree\fileA
Okay, not that different, the filename now contains the pathname in front, but the rest looks similar as well.
好的,没有什么不同,文件名现在包含前面的路径名,但其余部分看起来也相似。
As the example shows, even the directory object already imlements the RecursiveIteratorinterface, this is not yet enough to make foreachtraverse the whole directory tree. This is where the RecursiveIteratorIteratorcomes into action. Example 4shows how:
如示例所示,即使目录对象已经实现了RecursiveIterator接口,这还不足以foreach遍历整个目录树。这就是RecursiveIteratorIterator行动的地方。示例 4显示了如何:
$files = new RecursiveIteratorIterator($dir);
echo "[$path]\n";
foreach ($files as $file) {
echo " ├ $file\n";
}
Using the RecursiveIteratorIteratorinstead of just the previous $dirobject will make foreachto traverse over all files and directories in a recursive manner. This then lists all files, as the type of object iteration has been specified now:
使用RecursiveIteratorIterator而不是仅使用前一个$dir对象将以foreach递归方式遍历所有文件和目录。然后列出所有文件,因为现在已经指定了对象迭代的类型:
[tree]
├ tree\.
├ tree\..
├ tree\dirA\.
├ tree\dirA\..
├ tree\dirA\dirB\.
├ tree\dirA\dirB\..
├ tree\dirA\dirB\fileD
├ tree\dirA\fileB
├ tree\dirA\fileC
├ tree\fileA
This should already demonstrate the difference between flat and tree traversal. The RecursiveIteratorIteratoris able to traverse any tree-like structure as a list of elements. Because there is more information (like the level the iteration takes currently place), it is possible to access the iterator object while iterating over it and for example indent the output:
这应该已经证明了平面遍历和树遍历之间的区别。的RecursiveIteratorIterator是能够穿越任何树状结构,元素的列表。因为有更多信息(比如迭代当前发生的级别),可以在迭代时访问迭代器对象,例如缩进输出:
echo "[$path]\n";
foreach ($files as $file) {
$indent = str_repeat(' ', $files->getDepth());
echo $indent, " ├ $file\n";
}
And output of Example 5:
和示例 5 的输出:
[tree]
├ tree\.
├ tree\..
├ tree\dirA\.
├ tree\dirA\..
├ tree\dirA\dirB\.
├ tree\dirA\dirB\..
├ tree\dirA\dirB\fileD
├ tree\dirA\fileB
├ tree\dirA\fileC
├ tree\fileA
Sure this does not win a beauty contest, but it shows that with the recursive iterator there is more information available than just the linear order of keyand value. Even foreachcan only express this kind of linearity, accessing the iterator itself allows to obtain more information.
当然这不会赢得选美比赛,但它表明使用递归迭代器可以获得更多信息,而不仅仅是key和value的线性顺序。即使foreach只能表达这种线性,访问迭代器本身可以获得更多信息。
Similar to the meta-information there are also different ways possible how to traverse the tree and therefore order the output. This is the Modeof the RecursiveIteratorIteratorand it can be set with the constructor.
与元信息类似,也有不同的方法可以遍历树并因此对输出进行排序。这是 的模式,RecursiveIteratorIterator它可以用构造函数设置。
The next example will tell the RecursiveDirectoryIteratorto remove the dot entries (.and ..) as we do not need them. But also the recursion mode will be changed to take the parent element (the subdirectory) first (SELF_FIRST) before the children (the files and sub-subdirs in the subdirectory):
下一个示例将告诉RecursiveDirectoryIterator删除点条目(.和..),因为我们不需要它们。但递归模式也将更改为在子元素(子目录中SELF_FIRST的文件和子子目录)之前先 ( )取父元素(子目录):
$dir = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST);
echo "[$path]\n";
foreach ($files as $file) {
$indent = str_repeat(' ', $files->getDepth());
echo $indent, " ├ $file\n";
}
The output now shows the subdirectory entries properly listed, if you compare with the previous output those were not there:
输出现在显示正确列出的子目录条目,如果您与之前的输出进行比较,这些条目不存在:
[tree]
├ tree\dirA
├ tree\dirA\dirB
├ tree\dirA\dirB\fileD
├ tree\dirA\fileB
├ tree\dirA\fileC
├ tree\fileA
The recursion mode therefore controls what and when a brach or leaf in the tree is returned, for the directory example:
因此,递归模式控制返回树中的分支或叶的内容和时间,对于目录示例:
LEAVES_ONLY(default): Only list files, no directories.SELF_FIRST(above): List directory and then the files in there.CHILD_FIRST(w/o example): List files in subdirectory first, then the directory.
LEAVES_ONLY(默认):只列出文件,不列出目录。SELF_FIRST(上图):列出目录,然后列出其中的文件。CHILD_FIRST(无示例):首先列出子目录中的文件,然后是目录。
Output of Example 5with the two other modes:
带有其他两种模式的示例 5 的输出:
LEAVES_ONLY CHILD_FIRST
[tree] [tree]
├ tree\dirA\dirB\fileD ├ tree\dirA\dirB\fileD
├ tree\dirA\fileB ├ tree\dirA\dirB
├ tree\dirA\fileC ├ tree\dirA\fileB
├ tree\fileA ├ tree\dirA\fileC
├ tree\dirA
├ tree\fileA
When you compare that with standard traversal, all these things are not available. Recursive iteration therefore is a little bit more complex when you need to wrap your head around it, however it is easy to use because it behaves just like an iterator, you put it into a foreachand done.
当您将其与标准遍历进行比较时,所有这些都不可用。因此,当您需要将头环绕在它周围时,递归迭代会稍微复杂一点,但是它很容易使用,因为它的行为就像一个迭代器,您将它放入 aforeach并完成。
I think these are enough examples for one answer. You can find the full source-code as well as an example to display nice-looking ascii-trees in this gist: https://gist.github.com/3599532
我认为这些是一个答案的足够例子。您可以在此要点中找到完整的源代码以及显示漂亮的 ascii 树的示例:https: //gist.github.com/3599532
Do It Yourself:Make the
RecursiveTreeIteratorWork Line by Line.
自己动手:逐行完成
RecursiveTreeIterator工作。
Example 5demonstrated that there is meta-information about the iterator's state available. However, this was purposefully demonstrated withinthe foreachiteration. In real life this naturally belongs inside the RecursiveIterator.
示例 5演示了有关迭代器状态的元信息可用。然而,这在foreach迭代中是有目的地展示的。在现实生活中这自然属于里面RecursiveIterator。
A better example is the RecursiveTreeIterator, it takes care of indenting, prefixing and so on. See the following code fragment:
一个更好的例子是RecursiveTreeIterator,它负责缩进、前缀等。请参阅以下代码片段:
$dir = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$lines = new RecursiveTreeIterator($dir);
$unicodeTreePrefix($lines);
echo "[$path]\n", implode("\n", iterator_to_array($lines));
The RecursiveTreeIteratoris intended to work line by line, the output is pretty straight forward with one little problem:
在RecursiveTreeIterator旨在通过线工作线,输出是相当有一个小问题直截了当:
[tree]
├ tree\dirA
│ ├ tree\dirA\dirB
│ │ └ tree\dirA\dirB\fileD
│ ├ tree\dirA\fileB
│ └ tree\dirA\fileC
└ tree\fileA
When used in combination with a RecursiveDirectoryIteratorit displays the whole pathname and not just the filename. The rest looks good. This is because the file-names are generated by SplFileInfo. Those should be displayed as the basename instead. The desired output is the following:
当与 a 结合使用时,RecursiveDirectoryIterator它会显示整个路径名,而不仅仅是文件名。其余的看起来不错。这是因为文件名是由SplFileInfo. 那些应该显示为基本名称。所需的输出如下:
/// Solved ///
[tree]
├ dirA
│ ├ dirB
│ │ └ fileD
│ ├ fileB
│ └ fileC
└ fileA
Create a decorator class that can be used with RecursiveTreeIteratorinstead of the RecursiveDirectoryIterator. It should provide the basename of the current SplFileInfoinstead of the pathname. The final code fragment could then look like:
创建一个装饰器类,可以RecursiveTreeIterator代替RecursiveDirectoryIterator. 它应该提供当前SplFileInfo的基名而不是路径名。最终的代码片段可能如下所示:
$lines = new RecursiveTreeIterator(
new DiyRecursiveDecorator($dir)
);
$unicodeTreePrefix($lines);
echo "[$path]\n", implode("\n", iterator_to_array($lines));
These fragments including $unicodeTreePrefixare part of the gist in Appendix: Do It Yourself: Make the RecursiveTreeIteratorWork Line by Line..
这些片段包括$unicodeTreePrefix在部分要点附录:自己动手:使RecursiveTreeIterator通过线工作线。.
回答by salathe
What is the difference of
IteratorIteratorandRecursiveIteratorIterator?
IteratorIterator和的区别是RecursiveIteratorIterator什么?
To understand the difference between these two iterators, one must first understand a little bit about the naming conventions used and what we mean by "recursive" iterators.
要理解这两个迭代器之间的区别,首先必须了解所使用的命名约定以及我们所说的“递归”迭代器的含义。
Recursive and non-recursive iterators
递归和非递归迭代器
PHP has non-"recursive" iterators, such as ArrayIteratorand FilesystemIterator. There are also "recursive" iterators such as the RecursiveArrayIteratorand RecursiveDirectoryIterator. The latter have methods enabling them to be drilled down into, the former do not.
PHP 具有非“递归”迭代器,例如ArrayIterator和FilesystemIterator。还有“递归”迭代器,例如RecursiveArrayIteratorand RecursiveDirectoryIterator。后者具有使它们能够被深入研究的方法,而前者则没有。
When instances of these iterators are looped over on their own, even the recursive ones, the values only come from the "top" level even if looping over a nested array or directory with sub-directories.
当这些迭代器的实例自己循环时,即使是递归的,即使循环嵌套数组或带有子目录的目录,值也仅来自“顶级”级别。
The recursive iterators implementrecursive behaviour (via hasChildren(), getChildren()) but do not exploitit.
递归迭代器实现递归行为(通过hasChildren(), getChildren())但不利用它。
It might be better to think of the recursive iterators as "recursible" iterators, they have the abilityto be iterated recursively but simply iterating over an instance of one of these classes will not do that. To exploit the recursive behaviour, keep reading.
将递归迭代器视为“可递归”迭代器可能会更好,它们具有递归迭代的能力,但简单地迭代这些类之一的实例不会这样做。要利用递归行为,请继续阅读。
RecursiveIteratorIterator
递归迭代器迭代器
This is where the RecursiveIteratorIteratorcomes in to play. It has the knowledge of how to call the "recursible" iterators in such a way as to drill down into the structure in a normal, flat, loop. It puts the recursive behaviour into action. It essentially does the work of stepping over each of the values in the iterator, looking to see if there are "children" to recurse into or not, and stepping into and out of those collections of children. You stick an instance of RecursiveIteratorIteratorinto a foreach, and itdives into the structure so that you don't have to.
这是RecursiveIteratorIterator发挥作用的地方。它知道如何调用“可递归”迭代器,以便在正常的、扁平的循环中深入到结构中。它将递归行为付诸行动。它本质上执行遍历迭代器中的每个值的工作,查看是否有“子项”要递归进入或不存在,并逐步进入和退出这些子项集合。您将 的实例粘贴RecursiveIteratorIterator到 foreach 中,它会深入到结构中,这样您就不必这样做了。
If the RecursiveIteratorIteratorwas not used, you would have to write your own recursive loops to exploit the recursive behaviour, checking against the "recursible" iterator's hasChildren()and using getChildren().
如果RecursiveIteratorIterator未使用 ,则必须编写自己的递归循环来利用递归行为,检查“递归”迭代器hasChildren()并使用getChildren().
So that's a briefoverview of RecursiveIteratorIterator, how is it different from IteratorIterator? Well, you're basically asking the same sort of question as What is the difference between a kitten and a tree?Just because both appear in the same encyclopaedia (or manual, for the iterators) doesn't mean you should get confused between the two.
以上是对 的简要概述RecursiveIteratorIterator,它与 有什么不同IteratorIterator?好吧,您基本上问的是与小猫和树有什么区别一样的问题?仅仅因为两者都出现在同一个百科全书(或手册,对于迭代器)中并不意味着您应该在两者之间混淆。
IteratorIterator
迭代器迭代器
The job of the IteratorIteratoris to take any Traversableobject, and wrap it such that it satisfies the Iteratorinterface. A use for this is to then be able to apply iterator-specific behaviour on the non-iterator object.
的工作IteratorIterator是获取任何Traversable对象,并包装它以满足Iterator接口。这样做的一个用途是能够在非迭代器对象上应用特定于迭代器的行为。
To give a practical example, the DatePeriodclass is Traversablebut not an Iterator. As such, we can loop over its values with foreach()but cannot do other things that we ordinarily would with an iterator, such as filtering.
举一个实际的例子,DatePeriod类是Traversable但不是Iterator. 因此,我们可以foreach()使用迭代器循环它的值,但不能做我们通常使用迭代器做的其他事情,例如过滤。
TASK: Loop over the Mondays, Wednesdays and Fridays of the next four weeks.
任务:在接下来的四个星期的星期一、星期三和星期五循环。
Yes, this is trivial by foreach-ing over the DatePeriodand using an if()within the loop; but that's not the point of this example!
是的,通过foreach-ingDatePeriod和if()在循环中使用 an是微不足道的;但这不是这个例子的重点!
$period = new DatePeriod(new DateTime, new DateInterval('P1D'), 28);
$dates = new CallbackFilterIterator($period, function ($date) {
return in_array($date->format('l'), array('Monday', 'Wednesday', 'Friday'));
});
foreach ($dates as $date) { … }
The above snippet won't work because the CallbackFilterIteratorexpects an instance of a class that implements the Iteratorinterface, which DatePerioddoes not. However, since it is Traversablewe can easily satisfy that requirement by using IteratorIterator.
上面的代码段不起作用,因为它CallbackFilterIterator需要一个实现Iterator接口的类的实例,而DatePeriod它没有。但是,既然是Traversable这样,我们可以通过使用 轻松满足该要求IteratorIterator。
$period = new IteratorIterator(new DatePeriod(…));
As you can see, this has nothingwhatsoever to do with iterating over iterator classes nor recursion, and therein lies the difference between IteratorIteratorand RecursiveIteratorIterator.
正如你所看到的,这有什么无论如何做迭代的迭代器类,也不递归,其中存在的差异IteratorIterator和RecursiveIteratorIterator。
Summary
概括
RecursiveIteraratorIteratoris for iterating over a RecursiveIterator("recursible" iterator), exploiting the recursive behaviour that is available.
RecursiveIteraratorIterator用于迭代RecursiveIterator(“递归”迭代器),利用可用的递归行为。
IteratorIteratoris for applying Iteratorbehaviour to non-iterator, Traversableobjects.
IteratorIterator用于将Iterator行为应用于非迭代器Traversable对象。
回答by Tchoupi
When used with iterator_to_array(), RecursiveIteratorIteratorwill recursively walk the array to find all the values. Meaning that it will flatten the original array.
与 一起使用时iterator_to_array(),RecursiveIteratorIterator将递归遍历数组以查找所有值。这意味着它将展平原始数组。
IteratorIteratorwill keep the original hierarchical structure.
IteratorIterator将保持原来的层次结构。
This example will show you clearly the difference:
这个例子会清楚地告诉你区别:
$array = array(
'ford',
'model' => 'F150',
'color' => 'blue',
'options' => array('radio' => 'satellite')
);
$recursiveIterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
var_dump(iterator_to_array($recursiveIterator, true));
$iterator = new IteratorIterator(new ArrayIterator($array));
var_dump(iterator_to_array($iterator,true));
回答by javad shariaty
RecursiveDirectoryIterator it displays the whole pathname and not just the filename. The rest looks good. This is because the file-names are generated by SplFileInfo. Those should be displayed as the basename instead. The desired output is the following:
RecursiveDirectoryIterator 它显示整个路径名而不仅仅是文件名。其余的看起来不错。这是因为文件名是由 SplFileInfo 生成的。那些应该显示为基本名称。所需的输出如下:
$path =__DIR__;
$dir = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($dir,RecursiveIteratorIterator::SELF_FIRST);
while ($files->valid()) {
$file = $files->current();
$filename = $file->getFilename();
$deep = $files->getDepth();
$indent = str_repeat('│ ', $deep);
$files->next();
$valid = $files->valid();
if ($valid and ($files->getDepth() - 1 == $deep or $files->getDepth() == $deep)) {
echo $indent, "├ $filename\n";
} else {
echo $indent, "└ $filename\n";
}
}
output:
输出:
tree
├ dirA
│ ├ dirB
│ │ └ fileD
│ ├ fileB
│ └ fileC
└ fileA


