Generators & Iterators
Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 62 of 91.
Generators provide a simple way to create iterators without implementing the full Iterator interface. A generator function uses yield instead of return to produce values one at a time, pausing execution between each value.
Here's a basic generator that produces a sequence of numbers:
<?php
function countTo(int $max): Generator {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (countTo(3) as $number) {
echo "$number\n";
}
Output:
1
2
3The key advantage is memory efficiency. Instead of building an entire array in memory, generators produce values on-demand. This is crucial when working with large datasets - a generator processing a million records uses the same memory as one processing ten.
Generators can also yield key-value pairs:
<?php
function userGenerator(): Generator {
yield 'admin' => 'Alice';
yield 'editor' => 'Bob';
}
foreach (userGenerator() as $role => $name) {
echo "$role: $name\n";
}
Output:
admin: Alice
editor: BobTo make your own classes iterable with foreach, implement the Iterator interface. However, for most cases, generators offer a cleaner solution with less boilerplate code. They're particularly useful in OOP when a class needs to expose a collection of items without loading everything into memory at once.
Challenge
EasyLet's build a product inventory system that uses generators to efficiently iterate through large collections without loading everything into memory at once. You'll create a class that stores products and provides generator methods to iterate through them in different ways.
You'll organize your code across three files:
Product.php— Create aProductclass that represents an item in inventory. Use constructor promotion to define a public$sku(string), a public$name(string), and a public$price(float).Inventory.php— Create anInventoryclass that manages a collection of products and provides generator methods to iterate through them. Include the Product file. The class should:- Have a private array property to store products
- Have a method
addProduct(Product $product)that adds a product to the collection - Have a generator method
allProducts(): Generatorthat yields each product one at a time - Have a generator method
expensiveProducts(float $minPrice): Generatorthat yields only products with a price greater than or equal to the given minimum, yielding key-value pairs where the key is the SKU and the value is the product
main.php— Include the Inventory file. You'll receive one input: a minimum price threshold.Create an
Inventoryand add these three products:- SKU:
"A001", Name:"Laptop", Price:999.99 - SKU:
"A002", Name:"Mouse", Price:29.99 - SKU:
"A003", Name:"Monitor", Price:349.99
First, iterate through
allProducts()and print each product's name on its own line.Then print an empty line, followed by iterating through
expensiveProducts()using the input threshold. For each expensive product, print"[sku]: [name] - $[price]"on its own line. Format the price with exactly 2 decimal places.- SKU:
This challenge demonstrates how generators let you iterate through collections lazily — each product is yielded only when requested, making this approach memory-efficient for large inventories. The key-value yielding in expensiveProducts() shows how generators can provide structured iteration data.
Cheat sheet
Generators provide a memory-efficient way to create iterators using yield instead of return. They produce values one at a time, pausing execution between each value.
Basic generator function:
<?php
function countTo(int $max): Generator {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (countTo(3) as $number) {
echo "$number\n";
}
Generators can yield key-value pairs:
<?php
function userGenerator(): Generator {
yield 'admin' => 'Alice';
yield 'editor' => 'Bob';
}
foreach (userGenerator() as $role => $name) {
echo "$role: $name\n";
}
The main advantage is memory efficiency - generators produce values on-demand rather than building entire arrays in memory. This is especially useful when working with large datasets or collections in OOP contexts.
Try it yourself
<?php
require_once 'Inventory.php';
// Read input
$minPrice = floatval(trim(fgets(STDIN)));
// TODO: Create an Inventory instance
// TODO: Add three products:
// SKU: "A001", Name: "Laptop", Price: 999.99
// SKU: "A002", Name: "Mouse", Price: 29.99
// SKU: "A003", Name: "Monitor", Price: 349.99
// TODO: Iterate through allProducts() and print each product's name
// TODO: Print an empty line
// TODO: Iterate through expensiveProducts() using $minPrice
// For each expensive product, print "[sku]: [name] - $[price]"
// Format price with exactly 2 decimal places
?>This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe $this KeywordMethodsPropertiesConstructor (__construct)Destructor (__destruct)Recap - Simple Calculator4Inheritance
Basic InheritanceThe parent:: KeywordMethod OverridingThe final KeywordAbstract ClassesRecap - Employee Hierarchy7Encapsulation
Public, Protected, PrivateAccess Modifiers in DepthGetters and SettersInformation HidingConstructor Promotion (8.0)Recap - Student Records System10Advanced OOP Concepts
Composition vs InheritanceDependency InjectionAnonymous ClassesEnums (PHP 8.1)Fibers (PHP 8.1)Object Cloning Deep DiveGenerators & Iterators2Namespaces & Autoloading
Introduction to NamespacesThe use KeywordPSR-4 Autoloading StandardComposer AutoloaderRecap - Organized Project5Interfaces & Contracts
Introduction to InterfacesImplementing InterfacesMultiple Interface ImplementInterface vs Abstract ClassType Hinting with InterfacesRecap - Shape Calculator8Magic Methods
Magic Methods Introduction__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Object Cloning__serialize & __unserializeRecap - Custom Collection11Type System & Error Handling
Type DeclarationsNullable TypesUnion & Intersection TypesException ClassesCustom Exception HierarchyTry, Catch, FinallyRecap - Form Validator14Project: Library Management
Project OverviewBook and User Classes3Class Properties
Instance vs Static PropertiesConstants in ClassesStatic Methods & PropertiesPrivate & Protected PropertiesReadonly Properties (PHP 8.1)Recap - Bank Account Manager6Polymorphism
Method Overriding RevisitedPolymorphism via InterfacesType Hinting & Union TypesLate Static BindingRecap - Payment Processor9Traits
Introduction to TraitsUsing Multiple TraitsTrait Conflict ResolutionAbstract Methods in TraitsTraits vs Inheritance12Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern