yield
Le mot-clé yield permet de créer des fonctions génératrices en PHP qui produisent des valeurs une à une, économisant la mémoire.
Introduction
Le mot-clé yield transforme une fonction PHP ordinaire en générateur — une fonction qui produit une séquence de valeurs une à une, se mettant en pause après chaque valeur et reprenant là où elle s'est arrêtée lorsque la valeur suivante est demandée. Cette page explique le fonctionnement de yield, comment produire des clés, comment envoyer des valeurs dans un générateur, la syntaxe de délégation yield from, et dans quels cas les générateurs économisent de la mémoire par rapport à la construction d'un tableau complet.
Une fonction devient un générateur dès qu'elle contient au moins un yield. L'appeler ne pas exécute le corps — elle retourne un objet Generator. Le corps s'exécute uniquement lors de l'itération, avançant jusqu'au prochain yield à chaque étape. Comme un générateur implémente l'interface Iterator, on le consomme généralement avec une boucle foreach.
Un premier générateur
Chaque yield remet une valeur à l'appelant et gèle la fonction jusqu'à ce que la valeur suivante soit demandée.
myGenerator() retourne un objet générateur au lieu de s'exécuter immédiatement. La boucle foreach en extrait les valeurs : à chaque passage, la fonction s'exécute jusqu'au prochain yield, émet cette valeur, puis se met en pause. La sortie est :
Hello World !Contrairement à une fonction qui construit et returne un tableau, les trois chaînes de caractères ne sont jamais toutes conservées en mémoire en même temps — chacune est produite à la demande. Comparez cela avec la façon dont une fonction normale utilise return pour renvoyer une seule valeur et se terminer.
Produire des clés
Un générateur peut produire des paires clé/valeur avec la syntaxe yield $key => $value, exactement comme un tableau associatif. Les clés sont disponibles dans foreach :
<?php
function settings()
{
yield "host" => "localhost";
yield "port" => 5432;
yield "user" => "admin";
}
foreach (settings() as $key => $value) {
echo "$key = $value\n";
}Sortie :
host = localhost
port = 5432
user = adminSi vous ne fournissez pas de clés, PHP numérote automatiquement les valeurs produites à partir de 0, tout comme un tableau indexé.
Les générateurs sont paresseux : une plage économe en mémoire
Le véritable avantage de yield est que les valeurs sont calculées uniquement lorsque nécessaire. Un générateur qui produit un million de nombres utilise une mémoire constante, tandis qu'un tableau d'un million de nombres les alloue tous d'avance.
<?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;Sortie :
500000500000La boucle ne construit jamais un tableau [1, 2, …, 1000000] ; seul un entier existe à la fois. C'est le modèle à adopter lors de la lecture de fichiers volumineux ligne par ligne ou de la diffusion en continu de lignes de base de données.
Retourner une valeur depuis un générateur
Un générateur peut également utiliser return pour exposer une valeur finale (PHP 7+). La valeur de retour ne fait pas partie de l'itération — vous la lisez ensuite avec getReturn() :
<?php
function counter()
{
yield 1;
yield 2;
return "done";
}
$gen = counter();
foreach ($gen as $value) {
echo $value . " ";
}
echo $gen->getReturn();Sortie :
1 2 doneAppeler getReturn() avant que le générateur n'ait fini d'itérer lève une exception, donc épuisez-le toujours en premier.
Envoyer des valeurs avec send()
Les générateurs sont bidirectionnels : une expression yield peut également recevoir une valeur envoyée par l'appelant via send(). C'est la base des coroutines.
<?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");Sortie :
Got: a
Got: bsend($value) reprend le générateur, faisant en sorte que l'expression yield en pause s'évalue à $value, puis s'exécute jusqu'au prochain yield.
Déléguer avec yield from
yield from (PHP 7+) produit chaque valeur d'un autre générateur, tableau ou Traversable, les aplatissant dans le générateur courant sans boucle manuelle :
<?php
function inner()
{
yield 2;
yield 3;
}
function outer()
{
yield 1;
yield from inner();
yield from [4, 5];
}
foreach (outer() as $value) {
echo $value . " ";
}Sortie :
1 2 3 4 5 Quand utiliser un générateur
- Séquences larges ou non bornées — lire un fichier de plusieurs gigaoctets ou un flux infini où il est impossible de tout contenir dans un tableau.
- Valeurs coûteuses dont vous pourriez ne pas avoir besoin — si le consommateur peut s'arrêter tôt (
break), un générateur évite de calculer le reste. - Code d'itération plus propre — remplacer une classe
Iteratorpersonnalisée par une simple fonction.
Évitez les générateurs lorsque vous avez besoin d'un accès aléatoire ($arr[42]), de count() les résultats à moindre coût, ou d'itérer plusieurs fois sur les mêmes données — un générateur ne peut être parcouru qu'une seule fois. Pour ces cas, construisez un tableau normal, éventuellement avec des fonctions PHP comme array_map.