Generatoren-Übersicht
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
Generatoren bieten eine einfache Möglichkeit, um einfache
Iteratoren zu erstellen,
ohne den Overhead oder die Komplexität der Erstellung einer Klasse zu
haben, die das Iterator-Interface implementiert.
Mit einem Generator können auf bequeme Weise Daten für foreach
-Schleifen
bereitgestellt werden, ohne ein Array im Speicher zu erzeugen, was dazu
führen kann, dass das Programm ein Speicherlimit überschreitet oder
beträchtliche Prozessorzeit benötigt. Alternativ kann eine Generatorfunktion
verwendet werden, die einer normalen
Funktion entspricht, bei der
aber keine einmalige
Rückgabe erfolgt, sondern
der Generator so oft wie nötig einen Wert abgibt (Stichwort: yield
), um
die Werte zu liefern, über die iteriert werden soll.
Wie bei Iteratoren ist ein wahlfreier Datenzugriff nicht möglich.
Ein einfaches Beispiel dazu ist, die range()-Funktion
durch einen Generator neu zu implementieren. Die
Standard-range()-Funktion generiert und liefert Arrays,
welche jeden Wert enthalten, was große Arrays zur Folge haben kann: zum
Beispiel hat der Aufruf range(0, 1000000) zur Folge,
dass weit über 100 MB an Speicher benötigt werden.
Als Alternative können wir einen xrange()
-Generator
implementieren, welcher immer nur genug Speicher benötigt, um ein
Iterator-Objekt zu erzeugen und intern den aktuellen
Zustand des Generators zu verfolgen, was sich als weniger als 1 Kilobyte
herausstellt.
Beispiel #1 Implementierung von range() als Generator
<?php
function xrange($start, $limit, $step = 1) {
if ($start <= $limit) {
if ($step <= 0) {
throw new LogicException('Schrittweite muss positiv sein');
}
for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Schrittweite muss negativ sein');
}
for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}
/*
* Hinweis: sowohl range() als auch xrange()
* erzeugen die gleiche Ausgabe.
*/
echo 'Einstellige ungerade Zahlen von range(): ';
foreach (range(1, 9, 2) as $zahl) {
echo "$zahl ";
}
echo "\n";
echo 'Einstellige ungerade Zahlen von xrange(): ';
foreach (xrange(1, 9, 2) as $zahl) {
echo "$zahl ";
}
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
Einstellige ungerade Zahlen von range(): 1 3 5 7 9
Einstellige ungerade Zahlen von xrange(): 1 3 5 7 9
Beim Aufruf einer Generatorfunktion wird ein neues Objekt der internen
Generator-Klasse zurückgegeben. Dieses Objekt
implementiert das Iterator-Interface in gleicher
Weise wie es ein forward-only Iterator-Objekt machen würde und stellt
Methoden zur Verfügung, die aufgerufen werden können, um den Zustand des
Generators zu manipulieren, einschließlich des Sendens von Werten an,
und der Rückgabe von Werten von ihm.