Die Iterator-Schnittstellen von PHP 5

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.

Abbildung 3.1. Die Schnittstellen Iterator, IteratorAggregate und Traversable

Die Schnittstellen Iterator, IteratorAggregate und Traversable


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:

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.