W3docs

yield from

Ключевое слово yield from в PHP используется для делегирования генерации значений другому генератору, позволяя объединять несколько генераторов.

Введение

yield from — это выражение, позволяющее одному генератору делегировать работу другому итерируемому объекту: другому генератору, массиву или любому Traversable. Вместо того чтобы вручную перебирать внутренний источник и повторно выдавать каждый элемент, достаточно написать одну конструкцию yield from, и PHP самостоятельно передаст все значения (и ключи) вызывающему коду.

Это упрощает компоновку генераторов: вы можете строить большой поток значений из небольших, узкоспециализированных генераторных функций, не материализуя всю последовательность в памяти. Введённое в PHP 7.0, yield from является стандартным способом выравнивания вложенных генераторов.

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

Базовый синтаксис

yield from используется внутри генераторной функции и следует за любым итерируемым объектом:

yield from $iterable; // generator, array, or Traversable

Вот минимальный пример, объединяющий два генератора в один поток:

<?php

function myGenerator()
{
  yield "Hello";
  yield "World";
}

function myOtherGenerator()
{
  yield "!";
}

function myCombinedGenerator()
{
  yield from myGenerator();
  yield from myOtherGenerator();
}

foreach (myCombinedGenerator() as $value) {
  echo $value . " ";
}

myCombinedGenerator() не производит собственных значений — он полностью делегирует работу двум другим генераторам. При его вызове сначала выдаются значения из myGenerator(), затем из myOtherGenerator(), поэтому foreach выводит:

Hello World !

В одной функции можно свободно смешивать делегирование с обычными операторами yield:

<?php

function countToThree()
{
  yield 1;
  yield 2;
  yield 3;
}

function countToFive()
{
  yield from countToThree(); // delegates 1, 2, 3
  yield 4;                    // then yields its own values
  yield 5;
}

foreach (countToFive() as $value) {
  echo $value . " ";
}
// Output: 1 2 3 4 5

Делегирование массивам и другим итерируемым объектам

Источник после yield from не обязан быть генератором. Подойдёт любой массив или Traversable, что удобно для совместного выравнивания фиксированных и ленивых последовательностей:

<?php

function items()
{
  yield from ['apple', 'banana']; // an array
  yield from ['cherry'];
}

foreach (items() as $item) {
  echo $item . "\n";
}
// Output:
// apple
// banana
// cherry

Как обрабатываются ключи

yield from сохраняет ключи внутреннего итерируемого объекта, а не только значения. Это наиболее распространённая ловушка: ключи не перенумеровываются, поэтому два делегированных источника могут порождать дублирующиеся ключи.

<?php

function inner()
{
  yield 'a' => 1;
  yield 'b' => 2;
}

function outer()
{
  yield from inner();
  yield 'c' => 3;
}

foreach (outer() as $key => $value) {
  echo "$key => $value\n";
}
// Output:
// a => 1
// b => 2
// c => 3

Поскольку ключи сохраняются как есть, не следует рассчитывать на непрерывную последовательность 0, 1, 2, … при делегировании источникам с целочисленными ключами — если нужна переиндексация, соберите значения в массив с помощью iterator_to_array($gen, false).

Получение возвращаемого значения внутреннего генератора

Делегированный генератор может return финальное значение (отдельное от выдаваемых значений). Выражение yield from вычисляется как это возвращаемое значение, которое можно присвоить переменной:

<?php

function inner()
{
  yield 1;
  yield 2;
  return 'done';
}

function outer()
{
  $result = yield from inner();
  echo "Inner returned: $result\n";
  yield 3;
}

foreach (outer() as $value) {
  echo "Value: $value\n";
}
// Output:
// Value: 1
// Value: 2
// Inner returned: done
// Value: 3

Обратите внимание: возвращаемое значение внутреннего генератора захватывается конструкцией yield from — оно не передаётся в цикл foreach. До потребителя доходят только выданные значения (1, 2, 3).

Когда использовать yield from

Используйте yield from, когда вам нужно:

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

В сравнении с ручным повторным выдаванием (foreach ($inner as $v) { yield $v; }), yield from короче, автоматически сохраняет ключи и передаёт возвращаемое значение внутреннего генератора — поэтому предпочтительно использовать именно его при делегировании другому итерируемому объекту.

Связанные темы

  • yield — основа генераторов в PHP.
  • Цикл foreach — способ потребления значений генератора.
  • Функции PHP и return — строительные блоки, лежащие в основе генераторных функций.

Практика

Практика
Каково основное назначение оператора 'yield from' в PHP?
Каково основное назначение оператора 'yield from' в PHP?
Was this page helpful?