W3docs

yield

Das yield-Schlüsselwort erstellt in PHP Generatorfunktionen, die Werte einzeln liefern, pausieren und bei Bedarf fortgesetzt werden können.

Einführung

Das Schlüsselwort yield verwandelt eine gewöhnliche PHP-Funktion in einen Generator — eine Funktion, die eine Folge von Werten einzeln erzeugt, nach jedem Wert pausiert und dort fortfährt, wo sie aufgehört hat, sobald der nächste Wert angefordert wird. Diese Seite erklärt, wie yield funktioniert, wie man Schlüssel zurückgibt, wie man Werte in einen Generator sendet, die Delegierungssyntax yield from und wann Generatoren im Vergleich zur Erstellung eines vollständigen Arrays Speicher sparen.

Eine Funktion wird zu einem Generator, sobald sie mindestens ein yield enthält. Der Aufruf führt den Funktionskörper nicht aus — er gibt ein Generator-Objekt zurück. Der Körper läuft nur während der Iteration und geht bei jedem Schritt zum nächsten yield. Da ein Generator das Iterator-Interface implementiert, wird er üblicherweise mit einer foreach-Schleife verwendet.

Ein erster Generator

Jedes yield gibt einen Wert an den Aufrufer zurück und friert die Funktion ein, bis der nächste Wert angefordert wird.

php— editable, runs on the server

myGenerator() gibt ein Generatorobjekt zurück, anstatt sofort auszuführen. Die foreach-Schleife zieht Werte daraus: Bei jedem Durchlauf läuft die Funktion bis zum nächsten yield, gibt diesen Wert aus und pausiert. Die Ausgabe lautet:

Hello World !

Anders als eine Funktion, die ein Array aufbaut und mit return zurückgibt, werden alle drei Zeichenketten niemals gleichzeitig im Speicher gehalten — jede wird bei Bedarf erzeugt. Vergleichen Sie dies damit, wie eine normale Funktion return verwendet, um einen einzelnen Wert zurückzugeben und zu beenden.

Schlüssel zurückgeben

Ein Generator kann Schlüssel-/Wertpaare mit der Syntax yield $key => $value zurückgeben, genau wie ein assoziatives Array. Die Schlüssel sind innerhalb von foreach verfügbar:

<?php

function settings()
{
  yield "host" => "localhost";
  yield "port" => 5432;
  yield "user" => "admin";
}

foreach (settings() as $key => $value) {
  echo "$key = $value\n";
}

Ausgabe:

host = localhost
port = 5432
user = admin

Wenn Sie keine Schlüssel angeben, nummeriert PHP die zurückgegebenen Werte automatisch ab 0, genau wie ein indiziertes Array.

Generatoren sind lazy: ein speicherfreundlicher Bereich

Der eigentliche Vorteil von yield besteht darin, dass Werte nur bei Bedarf berechnet werden. Ein Generator, der eine Million Zahlen erzeugt, verwendet konstanten Speicher, während ein Array mit einer Million Zahlen alle auf einmal reserviert.

<?php

function gen_range($start, $end)
{
  for ($i = $start; $i <= $end; $i++) {
    yield $i;
  }
}

$sum = 0;
foreach (gen_range(1, 1000000) as $n) {
  $sum += $n;
}

echo $sum;

Ausgabe:

500000500000

Die Schleife erstellt niemals ein [1, 2, …, 1000000]-Array; es existiert jeweils nur eine ganze Zahl. Dies ist das Muster, das man beim zeilenweisen Lesen großer Dateien oder beim Streamen von Datenbankzeilen verwenden sollte.

Einen Wert von einem Generator zurückgeben

Ein Generator kann auch return verwenden, um einen abschließenden Wert bereitzustellen (PHP 7+). Der Rückgabewert ist kein Teil der Iteration — man liest ihn anschließend mit getReturn():

<?php

function counter()
{
  yield 1;
  yield 2;
  return "done";
}

$gen = counter();
foreach ($gen as $value) {
  echo $value . " ";
}
echo $gen->getReturn();

Ausgabe:

1 2 done

Der Aufruf von getReturn(), bevor der Generator die Iteration abgeschlossen hat, löst eine Ausnahme aus — daher sollte man ihn zuerst vollständig durchlaufen.

Werte mit send() senden

Generatoren funktionieren in beide Richtungen: Ein yield-Ausdruck kann auch einen Wert empfangen, der vom Aufrufer über send() gesendet wird. Dies ist die Grundlage von Coroutinen.

<?php

function echoTimes()
{
  while (true) {
    $received = yield;
    echo "Got: $received\n";
  }
}

$gen = echoTimes();
$gen->current();      // prime the generator (run up to the first yield)
$gen->send("a");
$gen->send("b");

Ausgabe:

Got: a
Got: b

send($value) setzt den Generator fort, sodass der pausierte yield-Ausdruck zu $value ausgewertet wird, und läuft dann bis zum nächsten yield.

Delegieren mit yield from

yield from (PHP 7+) gibt jeden Wert eines anderen Generators, Arrays oder Traversable zurück und flacht es in den aktuellen Generator ein, ohne eine manuelle Schleife zu benötigen:

<?php

function inner()
{
  yield 2;
  yield 3;
}

function outer()
{
  yield 1;
  yield from inner();
  yield from [4, 5];
}

foreach (outer() as $value) {
  echo $value . " ";
}

Ausgabe:

1 2 3 4 5 

Wann einen Generator verwenden

  • Große oder unbegrenzte Sequenzen — beim Lesen einer mehrere Gigabyte großen Datei oder eines unendlichen Streams, bei dem es unmöglich ist, alles in einem Array zu halten.
  • Aufwändige Werte, die möglicherweise nicht benötigt werden — wenn der Verbraucher früh abbrechen könnte (break), vermeidet ein Generator die Berechnung des Rests.
  • Saubererer Iterationscode — Ersetzen einer benutzerdefinierten Iterator-Klasse durch eine einzelne Funktion.

Vermeiden Sie Generatoren, wenn Sie zufälligen Zugriff benötigen ($arr[42]), Ergebnisse günstig mit count() zählen oder dieselben Daten mehrfach durchlaufen möchten — ein Generator kann nur einmal durchlaufen werden. Erstellen Sie für diese Fälle ein normales Array, möglicherweise mit PHP-Funktionen wie array_map.

Übung

Übung
Was ist die Funktion des Schlüsselworts 'yield' in PHP?
Was ist die Funktion des Schlüsselworts 'yield' in PHP?
Was this page helpful?