Une fonction générateur ressemble à une fonction normale, excepté qu'au lieu de retourner une valeur, le yield d'un générateur contient autant de valeurs que nécessaire.
Lorsqu'une fonction générateur est appelée, elle retourne un objet que l'on peut parcourir. Lorsque vous parcourez cette objet (via une boucle foreach), PHP va appeler la fonction générateur chaque fois qu'il a besoin d'une valeur, puis, sauvegarder le statut du générateur lorsque le générateur génère une valeur, pouvant être ainsi repris lorsque la prochaine valeur est requise.
Lorsqu'il n'y a plus de valeurs à fournir, alors la fonction générateur sort, tout simplement, et le code appelant continue comme si un tableau n'avait plus de valeur.
Note:
Un générateur ne peut pas retourner une valeur : si vous tentez de retourner la valeur d'un générateur, une erreur de compilation sera émise. Une structure return vide est une syntaxe valide, mais est inutile, vide de sens et ne fera rien.
Le mot clé yield est le coeur d'une fonction générateur. Dans sa forme la plus simple, une structure yield ressemble à une structure return, excepté qu'au lieu de stopper l'exécution de la fonction, et retourner, yield fournit une valeur au code parcourant le générateur, et met en pause l'exécution de la fonction générateur.
Exemple #1 Un exemple simple de valeurs produites
<?php
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
// Notez que $i est préservé entre chaque valeur produite.
yield $i;
}
}
$generator = gen_one_to_three();
foreach ($generator as $value) {
echo "$value\n";
}
?>
L'exemple ci-dessus va afficher :
1 2 3
Note:
En interne, les clés séquentielles d'un entier seront associées avec les valeurs yield, exactement comme un tableau non-associatif.
Si vous utilisez yield dans un contexte d'expression (par exemple, à droite d'un assignement), vous devez entourer yield avec des paranthèses. Par exemple, ceci est valide :
$data = (yield $value);
Mais ceci ne l'est pas, et génèrera une erreur d'analyse :
$data = yield $value;
Cette syntaxe peut être utilisée en conjonction de la méthode send() sur les objets Générateur.
PHP supporte également les tableaux associatifs, et les générateurs ne sont pas différents. En plus de fournir des valeurs simples, comme nous l'avons vu plus haut, vous pouvez aussi fournir une clé dans le même temps.
La syntaxe pour fournir une paire clé/valeur est similaire à celle utilisée pour définir un tableau associatif ; comme ceci :
Exemple #2 Fourniture d'une paire clé/valeur
<?php
/* L'entrée sera des champs séparés par un point-virgule,
* dont le premier champ est un ID à utiliser comme clé. */
$input = <<<'EOF'
1;PHP;Likes dollar signs
2;Python;Likes whitespace
3;Ruby;Likes blocks
EOF;
function input_parser($input) {
foreach (explode("\n", $input) as $line) {
$fields = explode(';', $line);
$id = array_shift($fields);
yield $id => $fields;
}
}
foreach (input_parser($input) as $id => $fields) {
echo "$id:\n";
echo " $fields[0]\n";
echo " $fields[1]\n";
}
?>
L'exemple ci-dessus va afficher :
1: PHP Likes dollar signs 2: Python Likes whitespace 3: Ruby Likes blocks
Comme pour l'exemple de fournir de valeurs simples, la fourniture d'une paire clé/valeur dans un contexte d'expression requière que la structure yield soit entre parenthèses :
$data = (yield $key => $value);
Yield peut être appelé sans argument pour fournir une valeur nulle avec une clé automatique.
Exemple #3 Fourniture de valeurs nulles
<?php
function gen_three_nulls() {
foreach (range(1, 3) as $i) {
yield;
}
}
var_dump(iterator_to_array(gen_three_nulls()));
?>
L'exemple ci-dessus va afficher :
array(3) { [0]=> NULL [1]=> NULL [2]=> NULL }
Les fonctions générateur peuvent fournir des valeurs par référence. Ceci se fait de la même façon que le retour par référence depuis des fonctions : en ajoutant un ET commercial (&) au nom de la fonction.
Exemple #4 Fourniture de valeurs par référence
<?php
function &gen_reference() {
$value = 3;
while ($value > 0) {
yield $value;
}
}
/* Notez qu'il est possible de changer $number dans la boucle,
* et, du fait que le générateur fournit des références, $value
* dans gen_reference() change aussi. */
foreach (gen_reference() as &$number) {
echo (--$number).'... ';
}
?>
L'exemple ci-dessus va afficher :
2... 1... 0...