Signatur
Beschreibung
OuterIterator erweitert das Iterator-Interface um die Methode getInnerIterator(), die Zugriff auf den intern gekapselten Iterator bietet. Klassen, die dieses Interface implementieren, dienen als Dekoratoren oder Wrapper um bestehende Iteratoren – sie können deren Ausgabe filtern, transformieren, zusammenführen oder auf sonstige Weise anpassen, ohne den ursprünglichen Iterator zu verändern.
Typische Anwendungsfälle sind das Filtern von Datensätzen (wie bei FilterIterator), das Begrenzen der Iteration auf einen bestimmten Bereich (wie bei LimitIterator) oder das rekursive Durchlaufen verschachtelter Strukturen (wie bei RecursiveIteratorIterator). Alle diese SPL-Klassen implementieren intern OuterIterator.
Das Interface selbst erbt alle Methoden von Iterator (current(), key(), next(), rewind(), valid()) und ergänzt lediglich getInnerIterator(). Durch diesen Vertrag können Werkzeuge und Funktionen, die mit Iteratoren arbeiten, transparent auf den umhüllten Iterator zugreifen.
Eigene Wrapper-Klassen sollten in der Regel von den vorhandenen abstrakten SPL-Klassen wie IteratorIterator erben, anstatt OuterIterator direkt zu implementieren, um Boilerplate-Code zu vermeiden.
Beispiele
Eigener OuterIterator zum Transformieren von Werten
<?php
class UpperCaseIterator extends IteratorIterator implements OuterIterator
{
public function current(): string
{
return strtoupper(parent::current());
}
}
$data = new ArrayIterator(['hallo', 'welt', 'foo']);
$upper = new UpperCaseIterator($data);
foreach ($upper as $key => $value) {
echo $key . ': ' . $value . PHP_EOL;
}
// Zugriff auf den inneren Iterator
echo get_class($upper->getInnerIterator()); // ArrayIterator
OuterIterator direkt implementieren (ohne IteratorIterator)
<?php
class PrefixIterator implements OuterIterator
{
private Iterator $inner;
private string $prefix;
public function __construct(Iterator $inner, string $prefix)
{
$this->inner = $inner;
$this->prefix = $prefix;
}
public function getInnerIterator(): Iterator
{
return $this->inner;
}
public function current(): string
{
return $this->prefix . $this->inner->current();
}
public function key(): mixed
{
return $this->inner->key();
}
public function next(): void
{
$this->inner->next();
}
public function rewind(): void
{
$this->inner->rewind();
}
public function valid(): bool
{
return $this->inner->valid();
}
}
$items = new ArrayIterator(['Alice', 'Bob', 'Carol']);
$prefixed = new PrefixIterator($items, 'User: ');
foreach ($prefixed as $name) {
echo $name . PHP_EOL;
}
// Wichtig · Fallstricke
Beim direkten Implementieren von OuterIterator müssen alle fünf von Iterator geerbten Methoden vollständig implementiert werden. Für die meisten Anwendungsfälle ist es einfacher, von IteratorIterator abzuleiten und nur die benötigten Methoden zu überschreiben.
Achte darauf, dass getInnerIterator() immer den direkt eingeschlossenen Iterator zurückgibt – bei tief verschachtelten Wrappern gibt jede Ebene nur ihren unmittelbaren inneren Iterator zurück, nicht den ursprünglichen Quell-Iterator.