note 67839 deleted from language.oop5.iterations by bjori
| From: | bjori@php.net | Date: | Wed, 05 Jul 2006 21:14:34 +0000 |
| Subject: | note 67839 deleted from language.oop5.iterations by bjori | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-114430@lists.php.net to get a copy of this message | ||
Note Submitter: baldurien at bbnwn dot eu
Reason: 5
----
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.
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;
}
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 fetch your collection to set the current() object.
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...