PHP bietet mit den Schnittstellen Iterator und
IteratorAggregate
(Abbildung 3.1)
[7]
eine Integration des Iterator-Entwurfsmusters
in die Programmiersprache selbst: Objekte, die die Schnittstelle
Iterator anbieten, können mit dem foreach-Operator
verwendet werden. Aufgrund dieser Integration wollen wir das
Iterator-Entwurfsmuster im Rahmen der Sprachmerkmale diskutieren und nicht
im eigentlichen Teil über Entwurfsmuster.
Wendet man den foreach-Operator auf ein Objekt an, das die
Schnittstelle Iterator anbietet, so bedient sich der
foreach-Operator der folgenden Methoden, um an die Daten
des Objektes zu gelangen:
rewind() setzt den Iterator zurück auf das erste
Element der Menge.
valid() prüft, ob nach einem Aufruf von rewind()
oder next() ein aktuelles Element existiert.
key() liefert den Schlüssel des aktuellen
Elementes.
current() liefert den Wert des aktuellen Elementes.
next() setzt den Iterator auf das nächste Element
der Menge.
Beispiel 3.5
zeigt als Beispiel eine Implementierung der Schnittstelle Iterator,
die über die (durch Leerzeichen getrennten) Teile eines Strings iteriert.
Beispiel 3.5: Eine Implementierung der Schnittstelle Iterator
<?php
class StringIterator implements Iterator {
private $string;
private $position;
public function __construct($string) {
$this->string = explode(' ', $string);
}
public function rewind() {
$this->position = 0;
}
public function valid() {
return $this->position < sizeof($this->string);
}
public function key() {
return $this->position;
}
public function current() {
return $this->string[$this->position];
}
public function next() {
$this->position++;
}
}
?>Beispiel 3.6: Implizite Verwendung von Iteratoren mit dem foreach-Operator
<?php
require_once 'StringIterator.php';
$iterator = new StringIterator('Dies ist ein String.');
foreach ($iterator as $key => $value) {
print $value . ' ';
}
?>Dies ist ein String.
Das Iterieren eines Objektes, dessen Klasse die Schnittstelle
Iterator implementiert, kann neben der
impliziten Verwendung durch die Benutzung des foreach-Operators
(Beispiel 3.6)
auch explizit durch die Verwendung der in der Schnittstelle vereinbarten
Methoden erfolgen
(Beispiel 3.7).
Hierbei wird deutlich, dass die Methoden der Schnittstelle Iterator
den aus PHP 3 bekannten Funktionen für das Durchlaufen von assoziativen
Arrays (Beispiel 3.2)
entsprechen.
Beispiel 3.7: Explizite Verwendung von Iteratoren
<?php
require_once 'StringIterator.php';
$iterator = new StringIterator('Dies ist ein String.');
for ($iterator->rewind();
$iterator->valid();
$iterator->next()) {
$key = $iterator->key();
$value = $iterator->current();
print $value . ' ';
}
?>Dies ist ein String.
Bislang müssen wir für eine Klasse, für die eine entsprechende
Iterator-Klasse zur Verfügung steht, "von Hand" ein Iterator-Objekt
erzeugen. Hier hilft die Implementierung der Schnittstelle
IteratorAggregate durch die Klasse. Deren Methode
getIterator liefert ein Objekt der entsprechenden
Iterator-Klasse. Verwendet man ein Objekt, das die Schnittstelle
IteratorAggregate anbietet, mit dem
foreach-Operator, so ruft der PHP-Interpreter
automatisch getIterator auf und verwendet das
zurückgegebene Iterator-Objekt.
Beispiel 3.8
zeigt eine Klasse String, die die Schnittstelle
IteratorAggregate implementiert. Wird ein Objekt dieser
Klasse zusammen mit dem foreach-Operator verwendet, so
wird das String-Objekt unter Verwendung eines
StringIterator-Objektes durchlaufen, ohne dass dieses
von Hand erzeugt werden muss.
Beispiel 3.8: Eine Implementierung der Schnittstelle IteratorAggregate
<?php
require_once 'StringIterator.php';
class String implements IteratorAggregate {
private $string;
public function __construct($string = '') {
$this->string = $string;
}
public function getIterator() {
return new StringIterator($this->string);
}
// ...
}
$string = new String('Dies ist ein String.');
foreach ($string as $key => $value) {
print $value . ' ';
}
?>Dies ist ein String.
[7]
Intern benutzt PHP die Schnittstelle Traversable, um
Iterator und IteratorAggregate zu
gruppieren. Diese Schnittstelle kann von einer in PHP geschriebenen
Klasse nicht direkt implementiert werden und spielt nur eine Rolle
bei der Implementierung von PHP-Klassen im C-Code einer
PHP-Erweiterung.