PHP.nl

Generator syntax

Generator-syntaxis

Een generatorfunctie ziet eruit als een normale functie, behalve dat in plaats van een waarde terug te geven, een generator zoveel waarden als nodig is, yield. Elke functie die yield bevat, is een generatorfunctie.

Wanneer een generatorfunctie wordt aangeroepen, retourneert deze een object dat kan worden doorlopen. Wanneer je over dat object iterates (bijvoorbeeld via een foreach-lus), zal PHP de iteratiemethoden van het object aanroepen telkens wanneer het een waarde nodig heeft, en vervolgens de staat van de generator opslaan wanneer de generator een waarde yield, zodat deze kan worden hervat wanneer de volgende waarde vereist is.

Zodra er geen waarden meer zijn om te yielden, kan de generator eenvoudig terugkeren, en de aanroepende code gaat verder alsof een array geen waarden meer heeft.

Opmerking: > Een generator kan waarden retourneren, die kunnen worden opgehaald met Generator::getReturn.

yield-sleutelwoord

Het hart van een generatorfunctie is het yield-sleutelwoord. In zijn eenvoudigste vorm lijkt een yield-statement veel op een return-statement, behalve dat in plaats van de uitvoering van de functie te stoppen en terug te geven, yield in plaats daarvan een waarde biedt aan de code die over de generator loopt en de uitvoering van de generatorfunctie pauzeert.

Voorbeeld: Een eenvoudig voorbeeld van het yielden van waarden

<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        // Opmerking dat $i behouden blijft tussen yields.
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}
?>
1
2
3

Opmerking: > Intern zullen sequentiële gehele getal sleutels worden gekoppeld aan de yielded waarden, net als bij een niet-associatieve array.

Waarden yielden met sleutels

PHP ondersteunt ook associatieve arrays, en generators zijn daar geen uitzondering op. Naast het yielden van eenvoudige waarden, zoals hierboven getoond, kun je ook tegelijkertijd een sleutel yielden.

De syntaxis voor het yielden van een sleutel/waarde paar is zeer vergelijkbaar met die gebruikt wordt om een associatieve array te definiëren, zoals hieronder getoond.

Voorbeeld: Yielden van een sleutel/waarde paar

<?php
/*
 * De invoer is puntkomma-gescheiden velden, waarbij het eerste
 * veld een ID is die als sleutel moet worden gebruikt.
 */

$input = <<<'EOF'
1;PHP;Houdt van dollartekens
2;Python;Houdt van witruimtes
3;Ruby;Houdt van blokken
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";
}
?>
1:
    PHP
    Houdt van dollartekens
2:
    Python
    Houdt van witruimtes
3:
    Ruby
    Houdt van blokken

Null-waarden yielden

Yield kan zonder argument worden aangeroepen om een null-waarde te yielden met een automatische sleutel.

Voorbeeld: Yielden van nulls

<?php
function gen_three_nulls() {
    foreach (range(1, 3) as $i) {
        yield;
    }
}

var_dump(iterator_to_array(gen_three_nulls()));
?>
array(3) {
  [0]=>
  NULL
  [1]=>
  NULL
  [2]=>
  NULL
}

Waarden yielden via referentie

Generatorfuncties zijn in staat om waarden te yielden via referentie evenals via waarde. Dit gebeurt op dezelfde manier als het retourneren van referenties vanuit functies: door een ampersand voor de functienaam te plaatsen.

Voorbeeld: Waarden yielden via referentie

<?php
function &gen_reference() {
    $value = 3;

    while ($value > 0) {
        yield $value;
    }
}

/*
 * Opmerking dat we $number binnen de lus kunnen veranderen, en
 * omdat de generator referenties yieldt, verandert $value
 * binnen gen_reference().
 */
foreach (gen_reference() as &$number) {
    echo (--$number).'... ';
}
?>
2... 1... 0...

Generatordelegatie via yield from

Generatordelegatie stelt je in staat om waarden van een andere generator, object, of array te yielden door gebruik te maken van het yield from-sleutelwoord. De buitenste generator zal dan alle waarden van de binnenste generator, object, of array yielden totdat dat niet langer geldig is, waarna de uitvoering in de buitenste generator zal doorgaan.

Als een generator wordt gebruikt met Traversable, zal de expressie ook elke waarde retourneren die door de binnenste generator is geretourneerd.

Let op: > ### Opslaan in een array (bijv. met iterator_to_array)

    reset de sleutels niet. Het behoudt
   de sleutels die door het `Traversable` object, of array zijn geretourneerd. Dus sommige waarden kunnen een gemeenschappelijke sleutel delen met een andere `Traversable` of array, wat, bij invoeging in een array, eerdere waarden met die sleutel zal overschrijven.

   Een veelvoorkomend geval waarin dit belangrijk is, is wanneer `iterator_to_array` standaard een gekeyde array retourneert, wat kan leiden tot mogelijk onverwachte resultaten.
    `iterator_to_array` heeft een tweede parameter die kan worden ingesteld op false om alle waarden te verzamelen terwijl de sleutels die door de generator zijn geretourneerd te negeren.

Voorbeeld: yield from

<?php
function inner() {
    yield 1; // sleutel 0
    yield 2; // sleutel 1
    yield 3; // sleutel 2
}
function gen() {
    yield 0; // sleutel 0
    yield from inner(); // sleutels 0-2
    yield 4; // sleutel 1
}
// geef false door als tweede parameter om een array [0, 1, 2, 3, 4] te krijgen
var_dump(iterator_to_array(gen()));
?>
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(4)
  [2]=>
  int(3)
}

Voorbeeld: Basisgebruik van yield from

<?php
function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    yield 9;
    yield 10;
}

function seven_eight() {
    yield 7;
    yield from eight();
}

function eight() {
    yield 8;
}

foreach (count_to_ten() as $num) {
    echo "$num ";
}
?>
1 2 3 4 5 6 7 8 9 10

Voorbeeld: yield from en return-waarden

<?php
function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    return yield from nine_ten();
}

function seven_eight() {
    yield 7;
    yield from eight();
}

function eight() {
    yield 8;
}

function nine_ten() {
    yield 9;
    return 10;
}

$gen = count_to_ten();
foreach ($gen as $num) {
    echo "$num ";
}
echo $gen->getReturn();
?>
1 2 3 4 5 6 7 8 9 10

Documentatie