Что означает yield в PHP?



Я недавно наткнулся на этот код:



function xrange($min, $max) 
{
for ($i = $min; $i <= $max; $i++) {
yield $i;
}
}


Я никогда такого не видел yield ключевое слово раньше. Пытаюсь запустить код я получаю




ошибка синтаксического анализа: синтаксическая ошибка, неожиданный T_VARIABLE в строке x




что это yield ключевое слово? Это даже действительный PHP? И если да, то как мне его использовать?

764   5  

5 ответов:

что это yield?

The yield ключевое слово возвращает данные из функции генератора:

сердцем функции генератора является ключевое слово yield. В своей простейшей форме оператор yield выглядит так же, как оператор return, за исключением того, что вместо остановки выполнения функции и возврата, yield вместо этого предоставляет значение коду, проходящему через генератор, и приостанавливает выполнение генератора функция.

что такое функция генератора?

функция генератора эффективно является более компактным и эффективным способом записи итератор. Это позволяет определить функцию (ваш xrange), что составит вычислить и возвратить значения пока вы петля над ним:

foreach (xrange(1, 10) as $key => $value) {
    echo "$key => $value", PHP_EOL;
}

это создаст следующий вывод:

0 => 1
1 => 2
…
9 => 10

вы также можете контролировать $key на foreach С помощью

yield $someKey => $someValue;

в функции генератора, $someKey это то, что вы хотите появиться для $key и $someValue являясь стоимостью в $val. В примере вопроса это $i.

в чем разница с нормальными функциями?

теперь вы можете задаться вопросом, почему мы не просто используем родной PHP range функции для достижения этого вывода. И ты прав. Результат будет таким же. Разница как мы туда попали.

при использовании range PHP, выполнит его, создаст весь массив чисел в памяти и return это весь массив до foreach цикл, который затем пройдет по нему и выведет значения. Другими словами,foreach будет работать на сам массив. Элемент

yield ключевое слово служит для определения "генераторов" в PHP 5.5. Хорошо, тогда что такое генератор?

From php.net:

генераторы обеспечивают простой способ реализации простых итераторов без накладных расходов или сложности реализации класса, реализующего интерфейс итератора.

генератор позволяет писать код, который использует foreach для итерации по набору данных без необходимости создания массива в памяти, что может привести к превышению лимита памяти или потребовать значительного времени обработки для создания. Вместо этого вы можете написать функцию генератора, которая является такой же, как и обычная функция, за исключением того, что вместо однократного возврата генератор может давать столько раз, сколько ему нужно, чтобы обеспечить значения, которые будут повторяться.

отсюда: генераторы = генераторы, Другие функции (просто простые функции) = функции.

Итак, они полезны когда:

  • вам нужно делать простые вещи (или простые вещи);

    генератор действительно намного проще, чем реализация интерфейса итератора. с другой стороны, ofcource, что генераторы менее функциональны. сравнивать их.

  • вам нужно генерировать большие объемы памяти для сохранения данных;

    на самом деле для экономии памяти мы можем просто генерировать необходимые данные через функции каждый цикл итерации, а после итерации использовать мусор. так вот основные моменты - четкий код и, вероятно, производительность. посмотрим, что лучше для ваших нужд.

  • вам нужно сгенерировать последовательность, которая зависит от промежуточных значений;

    Это продолжение предыдущей мысли. генераторы могут сделать вещи проще по сравнению с функциями. проверьте пример Фибоначчи, и постараемся сделать последовательность без генератора. Также генераторы могут работать быстрее в этом случае, по крайней мере, из-за хранения промежуточных значений в локальных переменных;

  • вам нужно улучшить производительность.

    они могут работать быстрее, чем функции в некоторых случаях (см. предыдущий преимущество);

простой пример:

<?php
echo '#start main# ';
function a(){
    echo '{start[';
    for($i=1; $i<=9; $i++)
        yield $i;
    echo ']end} ';
}
foreach(a() as $v)
    echo $v.',';
echo '#end main#';
?>

выход

#start main# {start[1,2,3,4,5,6,7,8,9,]end} #end main#

эта функция с помощью yield:

function a($items) {
    foreach ($items as $item) {
        yield $item + 1;
    }
}

почти такой же, как этот один без:

function b($items) {
    $result = [];
    foreach ($items as $item) {
        $result[] = $item + 1;
    }
    return $result;
}

С той лишь разницей, что a() возвращает a генератор и b() простой массив. Вы можете повторить на обоих.

кроме того, первый не выделяет полный массив и поэтому менее требователен к памяти.

С yield вы можете легко описать точки останова между несколькими задачами в одной функции. Вот и все, ничего особенного.

$closure = function ($injected1, $injected2, ...){
    $returned = array();
    //task1 on $injected1
    $returned[] = $returned1;
//I need a breakpoint here!!!!!!!!!!!!!!!!!!!!!!!!!
    //task2 on $injected2
    $returned[] = $returned2;
    //...
    return $returned;
};
$returned = $closure($injected1, $injected2, ...);

если task1 и task2 тесно связаны, но вам нужна точка останова между ними, чтобы сделать что-то еще:

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

тогда генераторы являются лучшим решением, потому что вам не нужно разбивать свой код на множество замыканий или смешивать его с другим кодом, или использовать обратные вызовы и т. д... Вы просто используете yield чтобы добавить точку останова, и вы можете продолжить с этой точки останова, если вы готовы.

добавить точку останова без генераторов:

$closure1 = function ($injected1){
    //task1 on $injected1
    return $returned1;
};
$closure2 = function ($injected2){
    //task2 on $injected2
    return $returned1;
};
//...
$returned1 = $closure1($injected1);
//breakpoint between task1 and task2
$returned2 = $closure2($injected2);
//...

добавить точку останова с генераторы

$closure = function (){
    $injected1 = yield;
    //task1 on $injected1
    $injected2 = (yield($returned1));
    //task2 on $injected2
    $injected3 = (yield($returned2));
    //...
    yield($returnedN);
};
$generator = $closure();
$returned1 = $generator->send($injected1);
//breakpoint between task1 and task2
$returned2 = $generator->send($injected2);
//...
$returnedN = $generator->send($injectedN);

Примечание: легко ошибиться с генераторами, поэтому всегда пишите модульные тесты перед их реализацией! примечание 2: использование генераторов в бесконечном цикле похоже на запись замыкания, которое имеет бесконечную длину...

Comments

    Ничего не найдено.