Генераторы и итераторы
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 62 из 91.
Генераторы предоставляют простой способ создавать итераторы без реализации полного интерфейса Iterator. Функция-генератор использует yield вместо return, чтобы выдавать значения по одному, приостанавливая выполнение между каждым значением.
Вот базовый генератор, который создаёт последовательность чисел:
<?php
function countTo(int $max): Generator {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (countTo(3) as $number) {
echo "$number\n";
}
Вывод:
1
2
3Ключевое преимущество — эффективность использования памяти. Вместо создания всего массива в памяти генераторы создают значения по требованию. Это особенно важно при работе с большими наборами данных: генератор, обрабатывающий миллион записей, использует столько же памяти, сколько генератор, обрабатывающий десять записей.
Generator также могут возвращать пары ключ-значение:
<?php
function userGenerator(): Generator {
yield 'admin' => 'Alice';
yield 'editor' => 'Bob';
}
foreach (userGenerator() as $role => $name) {
echo "$role: $name\n";
}
Вывод:
admin: Alice
editor: BobЧтобы сделать собственные классы итерируемыми с помощью foreach, реализуйте интерфейс Iterator. Однако в большинстве случаев генераторы предлагают более элегантное решение с меньшим количеством шаблонного кода. Они особенно полезны в OOP, когда классу нужно предоставить коллекцию элементов, не загружая всё в память одновременно.
Задание
ЛегкоДавайте создадим систему инвентаризации товаров, которая использует генераторы для эффективной итерации по большим коллекциям без одновременной загрузки всего в память. Вы создадите class, который хранит товары и предоставляет методы-generator для итерации по ним различными способами.
Вы организуете код в трех файлах:
Product.php: Создайте classProduct, представляющий товар в инвентаре. Используйте продвижение свойств конструктора, чтобы Define публичное$sku(string), публичное$name(string) и публичное$price(float).Inventory.php: Создайте classInventory, который управляет collection товаров и предоставляет методы-generator для итерации по ним. Подключите файл Product. class должен:- Иметь private свойство типа array для хранения товаров
- Иметь method
addProduct(Product $product), который добавляет товар в collection - Иметь метод-generator
allProducts(): Generator, который выдает каждый товар по одному - Иметь метод-generator
expensiveProducts(float $minPrice): Generator, который выдает only товары с ценой, большей или равной указанному минимуму, выдавая пары key-value, где key — SKU, а value — товар
main.php: Подключите файл Inventory. Вы получите один input: минимальный порог цены.Create
Inventoryи Add эти три товара:- SKU:
"A001", Name:"Laptop", Price:999.99 - SKU:
"A002", Name:"Mouse", Price:29.99 - SKU:
"A003", Name:"Monitor", Price:349.99
Сначала Iterate по
allProducts()и выведите Name каждого товара в отдельной строке.Затем выведите пустую строку, после чего Iterate по
expensiveProducts(), используя input-порог. Для каждого дорогого товара выведите"[sku]: [name] - $[price]"в отдельной строке. Format цену с exactly 2 знаками после десятичной точки.- SKU:
Это задание демонстрирует, как генераторы позволяют лениво итерироваться по коллекциям: каждый товар выдается только при запросе, благодаря чему такой подход эффективно использует память при работе с большими inventory. Выдача пар key-value в expensiveProducts() показывает, как генераторы могут предоставлять структурированные данные для итерации.
Попробуйте сами
<?php
require_once 'Inventory.php';
// Прочитать ввод
$minPrice = floatval(trim(fgets(STDIN)));
// TODO: Создать экземпляр Inventory
// TODO: Добавить три продукта:
// SKU: "A001", Name: "Laptop", Price: 999.99
// SKU: "A002", Name: "Mouse", Price: 29.99
// SKU: "A003", Name: "Monitor", Price: 349.99
// TODO: Пройтись по allProducts() и вывести имя каждого продукта
// TODO: Вывести пустую строку
// TODO: Пройтись по expensiveProducts() используя $minPrice
// Для каждого дорогого продукта вывести "[sku]: [name] - $[price]"
// Форматировать цену ровно с 2 знаками после запятой
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов10Продвинутые концепции ООП
Композиция и наследованиеВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP