Pyh.conf’25: a new PHP conference for the Russian-speaking community

Voting

: min(three, nine)?
(Example: nine)

The Note You're Voting On

baldurien at bbnwn dot eu
18 years ago
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
/**
* 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 array
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...

<< Back to user notes page

To Top