Вопрос проверяет понимание генераторов в PHP, ленивой итерации и работы ключевого слова yield.
Ключевое слово yield превращает обычную функцию в генератор, который возвращает значения по одному при обходе, а не все сразу. Вместо того чтобы формировать целый массив в памяти, генератор "выдаёт" значения по мере запроса через foreach. Это позволяет экономить память и эффективно работать с большими наборами данных. Также yield может возвращать пары ключ–значение и использоваться для сложных ленивых цепочек обработки. При каждом шаге выполнения функция "замораживается" в точке yield и продолжается с этого места при следующем запросе значения.
yield в PHPГенераторы — это удобный способ реализовать итераторы без создания отдельных классов, а yield — ключ к их работе.
Определение: Генератор — это специальный объект, который выдаёт последовательность значений по одному, сохраняя своё состояние между вызовами.
yield превращает функцию в генераторКогда внутри функции встречается yield, эта функция больше не возвращает обычное значение. Вместо этого она возвращает объект, реализующий интерфейс Generator.
Пример простого генератора:
php
function numbers(): Generator
{
yield 1;
yield 2;
yield 3;
}
foreach (numbers() as $value) {
echo $value, PHP_EOL;
}
Что происходит:
Вызов numbers() не начинает выполнение всей функции — он сразу создаёт объект Generator.
При первом обращении в foreach выполнение доходит до первого yield и возвращает значение 1.
Генератор "замораживается" в этой точке.
При следующей итерации выполнение продолжается после первого yield и идёт до следующего.
yield как ленивый источник данныхГлавная идея yield — ленивая (lazy) генерация значений.
Вместо того, чтобы:
загрузить 10 000 строк из базы
положить их в массив
затем пройти по массиву
мы можем выдавать строки по одной:
php
function fetchUsers(PDO $pdo): Generator
{
$stmt = $pdo->query('SELECT * FROM users');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield $row; // каждая строка отдаётся по мере чтения
}
}
Преимущества:
не занимается память под весь набор
можно обрабатывать поток данных "на лету"
удобно для больших файлов, результатов SQL и внешних API
yieldyield может возвращать не только значения, но и пары ключ–значение, аналогично массивам:
php
function mapIds(array $rows): Generator
{
foreach ($rows as $row) {
yield $row['id'] => $row; // ключ — id, значение — вся строка
}
}
В foreach вы можете получать и ключ, и значение:
php
foreach (mapIds($rows) as $id => $row) {
// ...
}
yield как выражение и yield fromyield — это выражение, а не только оператор, поэтому его можно использовать в контексте выражений:
php
function counter(int $start, int $end): Generator
{
for ($i = $start; $i <= $end; $i++) {
$incremented = $i + 1;
yield $incremented;
}
}
Также есть конструкция yield from, позволяющая делегировать генерацию другому генератору или массиву:
php
function all(): Generator
{
yield from [1, 2, 3];
yield from otherGenerator();
}
Генератор в PHP — полноценный объект, у которого есть методы:
current() — текущее значение
key() — текущий ключ
next() — перейти к следующему
rewind() — начать сначала (но см. ограничение по перемотке ниже)
send($value) — отправить значение обратно в генератор (для более продвинутых сценариев)
Пример использования send встречается реже, но позволяет строить "корутины" — более сложные взаимодействия между вызывающим кодом и генератором.
yield и генераторы — мощный инструмент для ленивой обработки данных. Они позволяют писать код, похожий на работу с массивами и foreach, но без больших затрат памяти и с возможностью обрабатывать потенциально бесконечные или очень большие последовательности.