Как работает метод send()?

132
10 ноября 2019, 18:20
  <?php
  function block()
  {
    while(true) {
      $string = yield;
      echo $string;
    }
  }
  $block = block();
  $block->send("Hello, world!<br />");
  $block->send("Hello, PHP!<br />");
?>

В документации написано, что он передает значение в генератор. Можете подробнее описать, как это происходит? Непонятно, что проверяет цикл while() и как $string получает переданную строку.

Answer 1

Непонятно, что проверяет цикл while()

ничего не проверяет, выполняет бесконечный цикл, чтобы вызывать send можно было произвольное число раз.

При вызове send генератор доходит выполняется до первого вызова yield, потом проходит следующую итерацию и останавливается перед новым вызовом. Параметр переданный в send() становится новым значением генератора. Т.е мы явно указываем новое значение, и проводим итерацию цикла.
сама переменная $string в данном случае для работы не нужна, генератор может выглядеть просто как

while(true) echo yield;

В документации как раз и описано. что при вызове send оператор yield вернет переданное значение, а при вызове next() вернет null. В более классической форме мы наоборот в цикле сами устанавливаем значение yield $value.

Как именно оно записывается в переменную $string? Интересует сам процесс. Вот дошел он до строки $string = yield и?

Согласно документации, при первом вызове генератор сначала выполняется до места где первый раз встречается yield, далее происходит установка текущего значения генератора. Мы это значение передаем явно в параметре send, то есть в данном месте значение генератора будет установлено.
Сам по себе оператор yield (некий аналог return) возвращает это самое текущее значение, которое и возвращается в переменную string. То есть:

  1. дошли до первого yield
  2. установили текущее значение
  3. присвоили его переменной (если вас смущает сама запись $string = yield), то представьте ее в виде $string = $this->current();
  4. вывели строку
  5. завершили итерацию и остановились перед следующим yield.

собственно добавив немного отладочного вывода можно эту цепочку проследить:

function block()
{
  echo "first run!\n";
  while(true) {
      echo "----- before yield\n";
      echo yield;
      echo " ---- after yield\n";
  }
}
$block = block();
echo "------------- call send()\n";
$block->send("Hello, world!\n");
echo "------------- call send()\n";
$block->send("Hello, PHP!\n");

на выходе получим

-- call send()
----- first run!
----- before yield
Hello, world!
---- after yield
----- before yield
-- call send()
Hello, PHP!
---- after yield
----- before yield
READ ALSO
Как ловить фатальные ошибки?

Как ловить фатальные ошибки?

Какой класс исключений использовать для перехвата фатальных ошибок, например, при попытке вывода несуществующей переменной? Есть общее...

111
Регулярка с числами. Удалить пробелы и после тире [закрыт]

Регулярка с числами. Удалить пробелы и после тире [закрыт]

Есть строка, которая содержит числа, — , пробелы между ними, и см: $string = 50 — 55 см

122
Проблема с php,и базой данных

Проблема с php,и базой данных

При переходе по ссылке Выдаёт ошибку http://домен/indexphp

132