Object Iteration

PHP 5 provides a way for objects to be defined so it is possible to iterate
through a list of items, with, for example a foreach statement. By default,
all visible properties will be used
for the iteration.

To clarify on php at moechofe's post, you CAN use the SPL to overide the array operator for a class. This, with the new features of object, and autoloading (among a buch of other things) has me completely sold on PHP5. You can also find this information on the SPL portion of the manual, but I'll post it here as well so it isn't passed up. The below Collection class will let you use the class as an array, while also using the foreach iterator:

if you in a string define classes that implements IteratorAggregate.you cant use the default;<?...public function getIterator() { return new MyIterator(\\$this-><What ever>);}..?>at least not if you want to use eval(<The string>).You have to use:<?...public function getIterator() { \\$arrayObj=new ArrayObject(\\$this-><What ever>); return \\$arrayObj->getIterator();}...?>

The iterator template from knj at aider dot dk does not yield correct results.If you do<?reset($a);next($a);echo current($a);?>where $a is defined over the suggested template, then the first element will be output, not the second, as expected.

In Java, iterator works like this :<?phpinterface Iterator<O> {boolean hasNext();O next();void remove();}?>But in php, the interface is this (I kept the generics and type because it's easier to understand)

1. valid() is more or less the equivalent of hasNext()2. next() is not the equivalent of java next(). It returns nothing, while Java next() method return the next object, and move to next object in Collections. PHP's next() method will simply move forward.

public O next() { if ( !hasNext()) throw new NoSuchElementException('at end of array'); return array[index++]; }

public void remove() { throw new UnsupportedOperationException('remove() not supported in array'); }}?>

And here is the same in php (using the appropriate function) :

<?php/** * Since the array is not mutable, it should use an internal * index over the number of elements for the previous/next * validation. */class ArrayIterator implements Iterator { private $array; public function __construct($array) { if ( !is_array($array)) throw new IllegalArgumentException('argument 0 is not an array');$this->array = array;$this->rewind(); } public function valid() { return current($this->array) !== false;// that's the bad method (should use arrays_keys, + index)} public function key() { return key($this->array); } public function current() { return current($this->array); } public function next() { if ( $this->valid()) throw new NoSuchElementException('at end of array');next($this->array); } public function previous() {// fails if current() = first item of arrayprevious($this->array); } public function rewind() {reset($this->array); }}?>

The difference is notable : don't expect next() to return something like in Java, instead use current(). This also means that you have to prefetch your collection to set the current() object. For instance, if you try to make a Directory iterator (like the one provided by PECL), rewind should invoke next() to set the first element and so on. (and the constructor should call rewind())

You should be prepared for your iterator's current method to be called before its next method is ever called. This certainly happens in a foreach loop. If your means of finding the next item is expensive you might want to use something like this

Please note that if you implement your iterator this way instead of with an IteratorAggregate you can not nest foreach-loops. This is because when the inner-loop is done the cursor is beyond the last element, then the outer-loop asks for the next element and finds the cursor beyond the last element as the innter-loop left it there.