Generator syntax

Оновлено: 12.05.2023

Функція-генератор виглядає так само, як і звичайна функція, за винятком того, що замість того, щоб повертати значення, генератор видає стільки значень, скільки йому потрібно. Будь-яка функція, що містить return, є функцією-генератором.

Коли викликається функція-генератор, вона повертає об'єкт, над яким можна виконувати ітерації. Під час ітерації над цим об'єктом (наприклад, за допомогою циклу foreach) PHP буде викликати методи ітерації об'єкта щоразу, коли йому буде потрібно значення, а потім збереже стан генератора, коли генератор видасть значення, щоб його можна було відновити, коли потрібно буде отримати наступне значення.

Як тільки не залишиться більше значень, генератор може просто завершити роботу, а викликаючий код продовжить виконання так, як якщо б у масиві закінчилися значення.

Зауважте:

Генератор може повертати значення, які можна отримати за допомогою функції Generator::getReturn().

Серцем функції-генератора є ключове слово yield. У своїй найпростішій формі оператор yield дуже схожий на оператор return, за винятком того, що замість того, щоб зупинити виконання функції і повернутися, yield надає значення коду, який циклічно перебирає генератор, і призупиняє виконання функції-генератора.

Приклад #1 Простий приклад отримання значень прибутковості

<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        // Note that $i is preserved between yields.
        yield $i;
    }
}

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

Вищенаведений приклад виведе:

Зауважте:

Внутрішньо послідовні цілі ключі будуть з'єднані з отриманими значеннями так само, як і у випадку з неасоціативним масивом.

PHP також підтримує асоціативні масиви, і генератори нічим не відрізняються від них. Крім простих значень, як показано вище, ви також можете одночасно виводити ключ.

Синтаксис для отримання пари ключ/значення дуже схожий на той, що використовується для визначення асоціативного масиву, як показано нижче.

Приклад #2 Отримання пари ключ/значення

<?php
/*
 * The input is semi-colon separated fields, with the first
 * field being an ID to use as a key.
 */

$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";
}
?>

Вищенаведений приклад виведе:

Yield можна викликати без аргументу, щоб отримати нульове значення з автоматичним ключем.

Приклад #3 Отримання нулів

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

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

Вищенаведений приклад виведе:

Функції-генератори можуть повертати значення як за посиланням, так і за значенням. Це робиться так само, як і повернення посилань з функцій: додаванням амперсанду до імені функції.

Приклад #4 Значення прибутковості за посиланням

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

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

/*
 * Note that we can change $number within the loop, and
 * because the generator is yielding references, $value
 * within gen_reference() changes.
 */
foreach (gen_reference() as &$number) {
    echo (--$number).'... ';
}
?>

Вищенаведений приклад виведе:

Делегування генератора дозволяє вам отримувати значення з іншого генератора, об'єкта або масиву за допомогою ключового слова yield from. Тоді зовнішній генератор видаватиме всі значення з внутрішнього генератора, об'єкта або масиву доти, доки вони не стануть недійсними, після чого виконання продовжиться у зовнішньому генераторі.

Якщо генератор використовується з yield from, вираз yield from також поверне будь-яке значення, повернуте внутрішнім генератором.

yield from не обнуляє ключі. Вона зберігає ключі, повернуті об'єктом або масивом Traversable. Таким чином, деякі значення можуть мати спільний ключ з іншими yield або yield from, які, будучи вставленими у масив, перезапишуть попередні значення з цим ключем.

Типовим випадком, коли це має значення, є повернення масиву з ключами за замовчуванням, що призводить до неочікуваних результатів. iterator_to_array() має другий параметр preserve_keys, який можна встановити у false, щоб зібрати всі значення, ігноруючи ключі, повернуті генератором.

Приклад #5 виведення з з допомогою iterator_to_array()

<?php
function inner() {
    yield 1; // key 0
    yield 2; // key 1
    yield 3; // key 2
}
function gen() {
    yield 0; // key 0
    yield from inner(); // keys 0-2
    yield 4; // key 1
}
// pass false as second parameter to get an array [0, 1, 2, 3, 4]
var_dump(iterator_to_array(gen()));
?>

Вищенаведений приклад виведе:

Приклад #6 Базове використання доходу від

<?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 ";
}
?>

Вищенаведений приклад виведе:

Приклад #7 вихідні та повернуті значення

<?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();
?>

Вищенаведений приклад виведе: