Beware of how works iterator in PHP if you come from Java!
In Java, iterator works like this :
<?php
interface 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)
<?php
interface Iterator<O> {
boolean valid();
mixed key();
O current();
void next();
void previous();
void rewind();
}
?>
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.
Here is a sample with an array, first in java, then in php :
<?php
class ArrayIterator<O> implements Iterator<O> {
private final O[] array;
private int index = 0;
public ArrayIterator(O[] array) {
this.array = array;
}
public boolean hasNext() {
return index < array.length;
}
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
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;
}
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() {
previous($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())
Also, another difference :
<?php
class ArrayIterable<O> implements Iterable<O> {
private final O[] array;
public ArrayIterable(O[] array) {
this.array = array;
}
public Iterator<O> iterator() {
return new ArrayIterator(array);
}
}
?>
When using an Iterable, in Java 1.5, you may do such loops :
<?php
for ( String s : new ArrayIterable<String>(new String[] {"a", "b"})) {
...
}
?>
Which is the same as :
<?php
Iterator<String> it = new ArrayIterable<String>(new String[] {"a", "b"});
while (it.hasNext()) {
String s = it.next();
...
}
?>
While in PHP it's not the case :
<?php
foreach ( $iterator as $current ) {
...
}
?>
Is the same as :
<?php
for ( $iterator->rewind(); $iterator->valid(); $iterator->next()) {
$current = $iterator->current();
...
}
?>
(I think we may also use IteratorAggregate to do it like with Iterable).
Take that in mind if you come from Java.
I hope this explanation is not too long...