yield from
La parola chiave yield from in PHP delega la generazione di valori a un altro generatore, permettendo di concatenare più generatori insieme.
Introduzione
yield from è un'espressione che consente a un generatore di delegare a un altro iterabile — un altro generatore, un array o qualsiasi Traversable. Invece di iterare sulla sorgente interna e re-produrre ogni elemento manualmente, si scrive un singolo yield from e PHP trasmette tutti i suoi valori (e chiavi) al chiamante automaticamente.
Questo rende facile comporre generatori: è possibile costruire un grande flusso di valori da piccole funzioni generatrici ben focalizzate senza mai materializzare l'intera sequenza in memoria. Introdotto in PHP 7.0, yield from è il metodo standard per appiattire generatori annidati.
Questo capitolo tratta la sintassi di base, come vengono gestite le chiavi, come acquisire il valore di ritorno di un generatore delegato e quando la delega è lo strumento giusto.
Sintassi di base
yield from appare all'interno di una funzione generatrice ed è seguito da qualsiasi iterabile:
yield from $iterable; // generator, array, or TraversableEcco un esempio minimale che combina due generatori in un unico flusso:
<?php
function myGenerator()
{
yield "Hello";
yield "World";
}
function myOtherGenerator()
{
yield "!";
}
function myCombinedGenerator()
{
yield from myGenerator();
yield from myOtherGenerator();
}
foreach (myCombinedGenerator() as $value) {
echo $value . " ";
}myCombinedGenerator() non produce alcun valore proprio — delega interamente agli altri due generatori. Richiamarlo produce prima i valori di myGenerator(), poi quelli di myOtherGenerator(), quindi il foreach stampa:
Hello World !È possibile mescolare liberamente la delega con le normali istruzioni yield nella stessa funzione:
<?php
function countToThree()
{
yield 1;
yield 2;
yield 3;
}
function countToFive()
{
yield from countToThree(); // delegates 1, 2, 3
yield 4; // then yields its own values
yield 5;
}
foreach (countToFive() as $value) {
echo $value . " ";
}
// Output: 1 2 3 4 5Delegare ad array e altri iterabili
La sorgente dopo yield from non deve necessariamente essere un generatore. Qualsiasi array o Traversable funziona, il che è comodo per appiattire sequenze fisse e lazy insieme:
<?php
function items()
{
yield from ['apple', 'banana']; // an array
yield from ['cherry'];
}
foreach (items() as $item) {
echo $item . "\n";
}
// Output:
// apple
// banana
// cherryCome vengono gestite le chiavi
yield from preserva le chiavi dell'iterabile interno, non solo i valori. Questo è l'errore più comune: le chiavi non vengono rinumerate, quindi due sorgenti delegate possono produrre chiavi duplicate.
<?php
function inner()
{
yield 'a' => 1;
yield 'b' => 2;
}
function outer()
{
yield from inner();
yield 'c' => 3;
}
foreach (outer() as $key => $value) {
echo "$key => $value\n";
}
// Output:
// a => 1
// b => 2
// c => 3Poiché le chiavi vengono mantenute così come sono, non fare affidamento su una sequenza continua 0, 1, 2, … quando si delega a sorgenti con chiavi intere — raccogliere i valori in un array con iterator_to_array($gen, false) se è necessario ri-indicizzarli.
Acquisire il valore di ritorno del generatore interno
Un generatore delegato può restituire con return un valore finale (separato dai valori che produce con yield). L'espressione yield from restituisce quel valore, che è possibile assegnare a una variabile:
<?php
function inner()
{
yield 1;
yield 2;
return 'done';
}
function outer()
{
$result = yield from inner();
echo "Inner returned: $result\n";
yield 3;
}
foreach (outer() as $value) {
echo "Value: $value\n";
}
// Output:
// Value: 1
// Value: 2
// Inner returned: done
// Value: 3Si noti che il valore di return del generatore interno viene acquisito da yield from — non viene inoltrato al ciclo foreach. Solo i valori prodotti con yield (1, 2, 3) raggiungono il consumatore.
Quando usare yield from
Ricorrere a yield from quando si vuole:
- Comporre generatori — costruire una pipeline da piccole funzioni generatrici con uno scopo specifico invece di un'unica grande funzione.
- Appiattire strutture annidate — percorrere ricorsivamente alberi o array annidati ed emettere un singolo flusso piatto di valori.
- Mantenere l'efficienza di memoria — i valori scorrono pigramente, uno alla volta, quindi non si tiene mai l'intera sequenza in memoria.
Rispetto al re-yield manuale (foreach ($inner as $v) { yield $v; }), yield from è più conciso, preserva le chiavi automaticamente e trasmette il valore di ritorno del generatore interno — quindi preferirlo ogni volta che si delega a un altro iterabile.
Argomenti correlati
- yield — la base dei generatori in PHP.
- foreach loop — come vengono consumati i valori del generatore.
- PHP functions e return — i mattoni fondamentali delle funzioni generatrici.