Artikelformat

Das Iterator-Interface

Diese Woche gibt es leider nur einen kurzen Artikel, da ich keinen vernünftigen Zugang ins Internet habe und somit meine Recherche-Möglichkeiten begrenzt sind. Darum betrachte ich heute kurz das Iterator-Interface. Da dieses Interface auch für PHP 5.3 wichtig ist, sollte dieses Interface dem interessierten Entwickler bekannt sein.

Das Interface stellt eine Möglichkeit bereit über eine Menge von Objekten zu iterieren. Ein Beispiel für eine Implementierung ist das array. In verschiedenen Projekten habe ich die Variante gesehen, dass die Objekte intern in einem Array verwaltet wurden. Sobald man über diese Objekte iterieren wollte, wurde das Array nach außen gegeben, damit man das foreach-Konstrukt nutzen konnte. Heutzutage sollte man lieber die Kapselung geschlossen lassen und das Iterator-Interface implementieren.

Als Beispiel entwickeln wir ein Objekt, dass mit einem String instanziiert wird und über das man anschließend mit foreach laufen kann. Es werden „Wörter“ als einzelne Rückgabewerte betrachtet. Also wird der Eingabe-String an einem Whitespace bzw. Komma-Zeichen gesplittet. Die „WordObject“-Klasse muss nun das mehrfach angesprochene Iterator-Interface implementieren. Hierzu sind die Methoden rewind, current, key, next und valid zu implementieren.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class WordObject implements Iterator {
 
    private $innerArray;
    private $pointer = 0;
 
    public function __construct($inputstring) {
        $this->innerArray = preg_split("/[\s,]+/",  trim($inputstring));
    }
 
    public function current() {
        return $this->innerArray[$this->pointer];
    }
 
    public function key() {
        return $this->pointer;
    }
 
    public function next() {
        ++$this->pointer;
    }
 
    public function rewind() {
        $this->pointer=0;
    }
 
    public function valid() {
        return isset($this->innerArray[$this->pointer]);
    }
}

Man kann das Objekt nun bspw. so nutzen:

1
2
3
4
5
$example = new WordObject("Hello World, this is a Iterator test");
 
foreach ($example as $key => $value) {
    echo $key . ": " . $value . "\n";
}

Dieser Code gibt dann – wie erwartet – folgende Ausgabe aus:

1
2
3
4
5
6
7
0: Hello
1: World
2: this
3: is
4: a
5: Iterator
6: test

Update und Anmerkung:
Wie in den Kommentaren angemerkt, kann man den obigen Code auch einfacher darstellen. Dafür muss das IteratorAggregate-Interface implementiert werden. Den Vorteil kann man vor allem deshalb nutzen, weil intern ein Array genutzt wird. Der Code für die vereinfachte Variante sieht so aus:

1
2
3
4
5
6
7
8
9
10
11
12
class WordObject implements IteratorAggregate {
 
    private $innerArray;
 
    public function __construct($inputstring) {
        $this->innerArray = preg_split("/[\s,]+/",  trim($inputstring));
    }
 
    public function getIterator() {
        return new ArrayObject($this->innerArray);
    }
}

4 Kommentare

  1. Also abgesehen davon, dass ich kein Fan von solchen Artikeln bin, weil die Dokumentation dazu schon sehr gut ist, mal eine Anmerkung…

    Wieso initialisierst du den die Eigenschaften der Klasse, wenn sie eh im Konstruktor in jedem Fall geschrieben / überschrieben werden?

    Gruß Seb

    Antworten
    • Ja okay. Du gehst dann aber davon aus, dass man den Iterator grundsätzlich kennt. Wenn dem nicht so ist, ist ein solcher Beitrag sicher interessant.

      Zur zweiten Anmerkung. Stimmt, die Attribute werden im Konstruktor überschrieben. Sowas passiert, wenn man etwas übermüdet programmiert. Wird angepasst 😉

  2. Dann sollte aber auch IteratorAggregate erwähnt werden, was in genau dem beschriebenen Anwendungsfall die Implementierung von current, key, next, rewind und valid erspart 😉

    Antworten
    • Stimmt, nur ist die Aussge des IteratorAggregate-Interfaces eine andere. Und du hast Recht, in diesem Fall merkt man kaum einen Unterschied. Werde ich heute abend als Anmerkung nachtragen.

Schreibe einen Kommentar

Pflichtfelder sind mit * markiert.