← Назад к вопросам

Что такое генераторы и в чём их преимущества?

1.6 Junior🔥 131 комментариев
#PHP Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое генераторы в PHP

Генераторы (generators) — это специальный тип функций в PHP, которые позволяют итерировать по набору данных без создания массива целиком в памяти. Ключевое отличие от обычных функций — использование ключевого слова yield вместо return. При каждом вызове yield функция приостанавливает выполнение и возвращает текущее значение, сохраняя внутреннее состояние для продолжения с того же места.

Базовый пример генератора

function generateNumbers(int $limit): Generator {
    for ($i = 0; $i < $limit; $i++) {
        yield $i * 2;
    }
}

foreach (generateNumbers(1000000) as $number) {
    echo $number . "\n";
}

Основные преимущества генераторов

1. Экономия памяти (ленивые вычисления)

Самое важное преимущество — генераторы не загружают все данные в память сразу, а выдают их по одному элементу:

// Проблема с обычным подходом:
function getAllUsers(): array {
    $users = [];
    for ($i = 0; $i < 1000000; $i++) {
        $users[] = ['id' => $i, 'name' => "User$i"]; // Массив из миллиона элементов!
    }
    return $users; // Требуется много памяти
}

// Решение с генератором:
function getAllUsersGenerator(): Generator {
    for ($i = 0; $i < 1000000; $i++) {
        yield ['id' => $i, 'name' => "User$i"]; // Только один элемент в памяти
    }
}

2. Улучшение производительности

Генераторы позволяют начать обработку данных немедленно, не дожидаясь генерации всего набора:

function readLargeFile(string $filename): Generator {
    $file = fopen($filename, 'r');
    while (!feof($file)) {
        yield fgets($file); // Чтение строки по строке
    }
    fclose($file);
}

// Обработка файла в 10 ГБ без загрузки в память
foreach (readLargeFile('huge_log.txt') as $line) {
    processLogLine($line); // Обработка начинается сразу
}

3. Гибкость и выразительность кода

Генераторы можно комбинировать в цепочки для создания пайплайнов обработки данных:

function filterEven(Generator $numbers): Generator {
    foreach ($numbers as $number) {
        if ($number % 2 === 0) {
            yield $number;
        }
    }
}

function squareNumbers(Generator $numbers): Generator {
    foreach ($numbers as $number) {
        yield $number * $number;
    }
}

// Создание пайплайна
$pipeline = squareNumbers(filterEven(generateNumbers(1000)));

4. Поддержка ключей и значений

Генераторы могут возвращать пары ключ-значение:

function getKeyValuePairs(): Generator {
    yield 'name' => 'Алексей';
    yield 'age' => 30;
    yield 'role' => 'developer';
}

foreach (getKeyValuePairs() as $key => $value) {
    echo "$key: $value\n";
}

5. Делегирование генерации

С PHP 7.0 доступно делегирование генераторов через yield from:

function firstGenerator(): Generator {
    yield 1;
    yield 2;
}

function secondGenerator(): Generator {
    yield from firstGenerator(); // Делегирование
    yield 3;
    yield 4;
}

Практические применения генераторов

Обработка больших данных

  • Чтение объемных CSV/JSON файлов
  • Потоковая обработка результатов БД
  • Пайплайны ETL (Extract, Transform, Load)

Работа с API

function paginatedApiCall(string $endpoint): Generator {
    $page = 1;
    do {
        $data = fetchFromApi($endpoint, $page);
        foreach ($data['items'] as $item) {
            yield $item;
        }
        $page++;
    } while ($data['has_more']);
}

Генерация последовательностей

function fibonacciSequence(int $count): Generator {
    $a = 0;
    $b = 1;
    for ($i = 0; $i < $count; $i++) {
        yield $a;
        [$a, $b] = [$b, $a + $b];
    }
}

Ограничения генераторов

  1. Однопроходность — генератор нельзя перемотать назад
  2. Нельзя получить количество элементов без итерации
  3. Нельзя получить случайный доступ к элементам

Сравнение с итераторами

Генераторы — это упрощенная синтаксическая надстройка над интерфейсом Iterator. Они позволяют достичь тех же целей с гораздо меньшим объемом кода:

// Реализация через Iterator (много кода)
class NumbersIterator implements Iterator { /* 50+ строк кода */ }

// Реализация через генератор (лаконично)
function numbersGenerator() { for($i=0;$i<10;$i++) yield $i; }

Заключение

Генераторы — это мощный инструмент для работы с последовательностями данных, особенно когда важны:

  • Эффективное использование памяти при больших объемах данных
  • Ленивые вычисления (загрузка по требованию)
  • Упрощение кода для итеративных операций

Их применение особенно оправдано в современных PHP-приложениях, работающих с Big Data, потоковой обработкой или любыми сценариями, где полная загрузка данных в память непрактична или невозможна. Генераторы стали неотъемлемой частью идиоматичного PHP, позволяя писать более эффективный и выразительный код.

Что такое генераторы и в чём их преимущества? | PrepBro