Generator-syntax

Från Wiki.linux.se
Hoppa till navigering Hoppa till sök

Generator-syntax

En generatorfunktion ser ut precis som en vanlig funktion, förutom att istället för att returnera ett värde, kan en generator avge (yield) så många värden som behövs. Alla funktioner som innehåller yield är en generatorfunktion.

När en generatorfunktion anropas returnerar den ett objekt som kan itereras över. När du itererar över det objektet (till exempel via en foreach-loop), kommer PHP att anropa objektets iterationsmetoder varje gång det behöver ett värde. PHP sparar sedan generatorns tillstånd när generatorn avger ett värde, så att den kan återupptas när nästa värde behövs.

När det inte finns fler värden att avge, kan generatorn helt enkelt returnera, och den anropande koden fortsätter precis som om en array hade tagit slut på värden.

Notera: En generator kan returnera värden, som kan hämtas med Generator::getReturn().

yield-nyckelordet

Hjärtat av en generatorfunktion är yield-nyckelordet. I sin enklaste form ser ett yield-uttalande ut mycket som ett return-uttalande, förutom att istället för att stoppa exekveringen av funktionen och returnera, så tillhandahåller yield istället ett värde till koden som itererar över generatorn och pausar exekveringen av generatorfunktionen.

Exempel #1 Ett enkelt exempel på att avge värden

<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        // Observera att $i bevaras mellan yield.
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator som $value) {
    echo "$value\n";
}
?>

Ovanstående exempel kommer att ge följande output:

1
2
3

Notera: Internt kommer sekventiella heltalsnycklar att paras ihop med de avgivna värdena, precis som med en icke-associativ array.

Avge värden med nycklar

PHP stöder också associativa arrayer, och generatorer är inte annorlunda. Förutom att avge enkla värden, som visat ovan, kan du också avge en nyckel samtidigt.

Syntaxen för att avge ett nyckel/värde-par är mycket lik den som används för att definiera en associativ array, som visas nedan.

Exempel #2 Avge ett nyckel/värde-par

<?php
/*
 * Inmatningen är semi-kolon-separerade fält, där det första
 * fältet är ett ID som används som nyckel.
 */

$input = <<<'EOF'
1;PHP;Gillar dollartecken
2;Python;Gillar blanksteg
3;Ruby;Gillar block
EOF;

function input_parser($input) {
    foreach (explode("\n", $input) som $line) {
        $fields = explode(';', $line);
        $id = array_shift($fields);

        yield $id => $fields;
    }
}

foreach (input_parser($input) som $id => $fields) {
    echo "$id:\n";
    echo "    $fields[0]\n";
    echo "    $fields[1]\n";
}
?>

Ovanstående exempel kommer att ge följande output:

1:
    PHP
    Gillar dollartecken
2:
    Python
    Gillar blanksteg
3:
    Ruby
    Gillar block

Avge null-värden

Yield kan anropas utan ett argument för att avge ett null-värde med en automatisk nyckel.

Exempel #3 Avge null-värden

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

var_dump(iterator_to_array(gen_three_nulls()));
?>

Ovanstående exempel kommer att ge följande output:

array(3) {
  [0]=>
  NULL
  [1]=>
  NULL
  [2]=>
  NULL
}

Avge genom referens

Generatorfunktioner kan avge värden genom referens såväl som genom värde. Detta görs på samma sätt som att returnera referenser från funktioner: genom att sätta ett &-tecken före funktionsnamnet.

Exempel #4 Avge värden genom referens

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

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

/*
 * Observera att vi kan ändra $number inom loopen, och
 * eftersom generatorn avger referenser, ändras $value
 * inom gen_reference().
 */
foreach (gen_reference() som &$number) {
    echo (--$number).'... ';
}
?>

Ovanstående exempel kommer att ge följande output:

2... 1... 0...

Generatordelegation via yield from

Generatordelegation gör det möjligt att avge värden från en annan generator, Traversable-objekt, eller array genom att använda yield from-nyckelordet. Den yttre generatorn kommer då att avge alla värden från den inre generatorn, objektet eller arrayen tills den inte längre är giltig, varefter exekveringen fortsätter i den yttre generatorn.

Om en generator används med yield from, kommer yield from-uttrycket också att returnera vilket värde som helst som returneras av den inre generatorn.

Varning: När man lagrar i en array (t.ex. med iterator_to_array()), återställer inte yield from nycklarna. Det bevarar nycklarna som returneras av Traversable-objektet eller arrayen. Därför kan vissa värden dela en gemensam nyckel med en annan yield eller yield from, vilket, vid insättning i en array, kommer att skriva över tidigare värden med den nyckeln.

Ett vanligt fall där detta är viktigt är när iterator_to_array() returnerar en array med nycklar som standard, vilket kan leda till oväntade resultat. iterator_to_array() har en andra parameter preserve_keys som kan sättas till false för att samla alla värden medan nycklarna som returneras av Generatorn ignoreras.

Exempel #5 yield from med iterator_to_array()

<?php
function inner() {
    yield 1; // nyckel 0
    yield 2; // nyckel 1
    yield 3; // nyckel 2
}
function gen() {
    yield 0; // nyckel 0
    yield from inner(); // nycklar 0-2
    yield 4; // nyckel 1
}
// Skicka false som andra parameter för att få en array [0, 1, 2, 3, 4]
var_dump(iterator_to_array(gen()));
?>

Ovanstående exempel kommer att ge följande output:

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(4)
  [2]=>
  int(3)
}

Exempel #6 Grundläggande användning av 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() som $num) {
    echo "$num ";
}
?>

Ovanstående exempel kommer att ge följande output:

1 2 3 4 5 6 7 8 9 10

Exempel #7 yield from och returvärden

<?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 som $num) {
    echo "$num ";
}
echo $gen->getReturn();
?>

Ovanstående exempel kommer att ge följande output:

1 2 3 4 5 6 7 8 9 10

Sidslut

Orginalhemsidan på Engelska : https://www.php.net/manual/en/language.fibers.php
PHP
Språkreferens
Språkreferens#Generatorer


Det här är en maskinöversättning av PHP-manualen till svenska. Om du hittar fel är vi tacksamma om du rapporterar dem via formuläret som finns på https://www.linux.se/kontaka-linux-se/