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.
Ein Generator ermöglicht es Code zu schreiben, der foreach nutzt, um über
eine Datenmenge zu iterieren, ohne ein Array im Speicher zu erzeugen,
was zur Überschreitung des Speicherlimits führen kann oder beträchtliche
Prozessorzeit benötigt. Alternativ können Sie eine Generatorfunktion
schreiben, 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.
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.