26

I was perusing the manual today and noticed the various iterators. To me, it seems like they are all somewhat pointless; I don't see a reason to use them unless you prefer their syntax, or don't know how to write a recursive function. Are there any reasons to use built-in iterators in PHP over just writing a loop or making a recursive method?

I'm only looking for factual responses, not subjective preferences (ie: I don't care if you think it's more "readable" or "more object-oriented", I want to know if they're faster, offer functionality that can't be achieved when rolling your own, etc.).

Teun Zengerink
  • 4,277
  • 5
  • 30
  • 32
mrjminer
  • 273
  • 3
  • 6
  • 5
    "more object-oriented" is not a subjective opinion; it digs right into the feature-set of your problem. If you deal with objects, it's not subjective to want to work with them in an object-oriented manner. – AlexanderJohannesen Jun 06 '11 at 02:05
  • 1
    I think that "more object-oriented" is a subjective opinion in this case because the implementation achieved by the iterators is not any more "object-oriented" than a custom implementation could be; they're not any more object oriented than an alternative object-oriented solution. – mrjminer Jun 06 '11 at 02:20
  • 1
    That's an odd comment, given that some iterators operate on specific objects that traditional methods won't work at all (which is a very important point). You can't treat objects as an array unless you convert them to an array, and often that is simply not possible; any non-tree structure will give you massive headaches. If you're iterating through a graph relying on the semantics of some relationships, this is impossible without iterators but often quite trivial with. So. No, not really subjective, unless you're Voltaire and delve into existentialism. :) – AlexanderJohannesen Jun 06 '11 at 02:28
  • Which iterator implements something that can't be done otherwise? I'll need to note it for future usage. – mrjminer Jun 06 '11 at 02:32
  • 2
    Most of mine. :) I do a lot of work traversing graphs and complex data models with lots of many-to-many, and so the concept of First, Next, Previous and Last have very different meaning than in an array. I could be at a node with 5 relationships, so what does Next mean? (It usually means heavy computation of jump-points and distance, often based on several parameters that change with the locality of the nodes in question) Think of Last meaning "the furthest away from the current node we can get", and then when you get there, now what does Next mean? Fun stuff. – AlexanderJohannesen Jun 06 '11 at 03:09

5 Answers5

20

The main advantage of iterators is that they abstract the concept of iteration. This means that any data providers can be used through the same interface. And that's exactly where you can take advantage of them:

  • Laziness
  • Reduced memory usage
  • Composition

Laziness

With data providers, the data is only fetched when you actually need it (eg. when you iterate).

Reduced memory usage

Iterators encourage you to process data iteratively, instead of buffering it in memory. While it is possible to do this without iterators, the abstractions they provide hide the implementation which makes them really easy to use.

Composition

What mario said.


Juozas Kaziukėnas recently wrote a blog post of how he could use iterators to emulate lazy evaluation in PHP. It goes into detail about some of the things I've mentioned.

igorw
  • 27,759
  • 5
  • 78
  • 90
19

I believe the main reason is versatility. They don't make things more readable and you can accomplish most of what the spl iterators do with a simple foreach.

But iterators can serve as sort of a compacted loop or loop source that you can pass around. You can have more diverse data sources than just a list/array. And the real advantage is that you can wrap or stack them for aggregation.

The naming is somewhat unobvious, but I guess you could use the AppendIterator to for example combine a static list of filenames and the result of a DirectoryIterator. Or otherwise wrap that in a LimitIterator instead of hardwiring that into a for condition. All of these are pretty basic features and can be done manually in a foreach. But at least RegexIterator and FilterIterator seem suitable to reduce some complexity.

But in the end it's really a stylistic choice. It would make most sense if you have custom objects which traverse something (for example a VFS object which can either point to real files or database entries). But even then you could just iterator_to_array convert such a list, and use a normal foreach-over-array.

The only case were it is really imperative to prefer iterators were if the data source is unlimited in size. Unfolded arrays for use in a foreach can consume more memory than an iterator which can retrieve element by element.

mario
  • 144,265
  • 20
  • 237
  • 291
  • I see what you mean with unlimited size data sources. I'm going to have to test memory/CPU usage with each when I get some time. – mrjminer Jun 06 '11 at 02:17
  • Can an array be a "data source unlimited in size"? If not, what's the point for ArrayIterators? – Muc May 09 '13 at 13:58
  • @Muc An array can't. As those hold their data in memory. But iterators can, as the input might be dynically resolved from files / database / socket input / urand etc. – mario May 09 '13 at 14:10
  • @mario Thanks, I see, now, the follow up question: why would I use an ArrayIterator? – Muc May 10 '13 at 15:27
  • Kind of late to the game, but an `ArrayIterator` is mainly useful if you need type safety for your array structure and want to utilize information hiding, as you should in OO. Of course it still behaves exactly the same as an array to the user, but that is the nice thing. – Fleshgrinder Oct 13 '15 at 17:30
12

The question can have very wide variety of answers, but proper answers probably can be summarized as: Iterator can be used for iterating anything more complex than simple array.

One example is some kind of ORM or query builder. Assume we have one - using it could look like that:

$friends = new Model_Friend();
$friends = $people->where('age','>',30)->where('gender','=','female');
foreach ($friends as $friend) {
    echo $friend->name;
}
Tadeck
  • 132,510
  • 28
  • 152
  • 198
9

One simple example: Implementing an object that can be accessed and traversed like an array. SimpleXML is a nice example of the powerful behavior that can be achieved with this.

To accomplish this you could implement the Iterator interface which defines the methods public current(), public key(), public next(), public rewind() and public valid().

Or you can simply implement the alternative IteratorAggregate interface which defines one method public getIterator() which simply returns an Iterator for the internal data you want to expose.

Be sure to check out the examples of the above Interfaces and you'll see the advantage.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • Thanks for the link to SimpleXML. I don't have time to dig into it right now, but a quick look revealed that it will be a good example. – mrjminer Jun 06 '11 at 02:26
  • That's the thing: you can have an object _also_ be traversable, along with _other_ functionality. So it lends itself to anything that's more complicated/advanced than just simply looping through some plain data structure. Otherwise it's just bloat, so remember KISS and YAGNI. – DanMan Sep 16 '16 at 09:49
1

Iterators are just as fast as anything else, but with an easier interface and perhaps more verbage to wrap it in. However, the main advantage is not what you may need right now, but how you can extend them to deal with your future problems (and they will come!), and that is what we old boys call "saving your future ass". :)

AlexanderJohannesen
  • 2,028
  • 2
  • 13
  • 26