Menu
Coddy logo textTech

Generadores e iteradores

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy. Lección 62 de 91.

Los generadores proporcionan una forma sencilla de crear iteradores sin implementar la interfaz completa Iterator. Una función generadora utiliza yield en lugar de return para producir valores uno a uno, pausando la ejecución entre cada valor.

Aquí tienes un generador básico que produce una secuencia de números:

<?php
function countTo(int $max): Generator {
    for ($i = 1; $i <= $max; $i++) {
        yield $i;
    }
}

foreach (countTo(3) as $number) {
    echo "$number\n";
}

Salida:

1
2
3

La ventaja clave es la eficiencia de memoria. En lugar de construir un array completo en memoria, los generadores producen valores bajo demanda. Esto es crucial al trabajar con conjuntos de datos grandes: un generador que procesa un millón de registros utiliza la misma memoria que uno que procesa diez.

Los generadores también pueden producir pares clave-valor:

<?php
function userGenerator(): Generator {
    yield 'admin' => 'Alice';
    yield 'editor' => 'Bob';
}

foreach (userGenerator() as $role => $name) {
    echo "$role: $name\n";
}

Salida:

admin: Alice
editor: Bob

Para hacer que tus propias clases sean iterables con foreach, implementa la interfaz Iterator. Sin embargo, en la mayoría de los casos, los generadores ofrecen una solución más limpia con menos código repetitivo. Son especialmente útiles en la POO cuando una clase necesita exponer una colección de elementos sin cargarlo todo en la memoria de una sola vez.

challenge icon

Desafío

Fácil

Construyamos un sistema de inventario de productos que use generadores para iterar eficientemente a través de colecciones grandes sin cargar todo en la memoria de una sola vez. Crearás una clase que almacene productos y proporcione métodos generadores para iterar a través de ellos de distintas maneras.

Organizarás tu código en tres archivos:

  • Product.php: Crea una clase Product que represente un artículo del inventario. Usa la promoción de constructores para definir un $sku (string) público, un $name (string) público y un $price (float) público.
  • Inventory.php: Crea una clase Inventory que administre una colección de productos y proporcione métodos generadores para iterar a través de ellos. Incluye el archivo Product. La clase debe:
    • Tener una propiedad de tipo array privada para almacenar los productos
    • Tener un método addProduct(Product $product) que agregue un producto a la colección
    • Tener un método generador allProducts(): Generator que produzca cada producto de uno en uno
    • Tener un método generador expensiveProducts(float $minPrice): Generator que produzca únicamente los productos cuyo precio sea mayor o igual que el mínimo indicado, produciendo pares clave-valor donde la clave sea el SKU y el valor sea el producto
  • main.php: Incluye el archivo Inventory. Recibirás una entrada: un umbral de precio mínimo.

    Crea un Inventory y agrega estos tres productos:

    • SKU: "A001", Nombre: "Laptop", Precio: 999.99
    • SKU: "A002", Nombre: "Mouse", Precio: 29.99
    • SKU: "A003", Nombre: "Monitor", Precio: 349.99

    Primero, itera a través de allProducts() e imprime el nombre de cada producto en su propia línea.

    Después imprime una línea vacía y, a continuación, itera a través de expensiveProducts() usando el umbral de entrada. Para cada producto caro, imprime "[sku]: [name] - $[price]" en su propia línea. Formatea el precio con exactamente 2 decimales.

Este desafío demuestra cómo los generadores permiten iterar de forma perezosa a través de colecciones: cada producto se produce únicamente cuando se solicita, lo que hace que este enfoque sea eficiente en cuanto a memoria para inventarios grandes. La producción de pares clave-valor en expensiveProducts() muestra cómo los generadores pueden proporcionar datos de iteración estructurados.

Pruébalo tú mismo

<?php

require_once 'Inventory.php';

// Leer entrada
$minPrice = floatval(trim(fgets(STDIN)));

// TODO: Crea una instancia de Inventory

// TODO: Añade tres productos:
// SKU: "A001", Nombre: "Laptop", Precio: 999.99
// SKU: "A002", Nombre: "Mouse", Precio: 29.99
// SKU: "A003", Nombre: "Monitor", Precio: 349.99

// TODO: Itera a través de allProducts() e imprime el nombre de cada producto

// TODO: Imprime una línea vacía

// TODO: Itera a través de expensiveProducts() usando $minPrice
// Para cada producto caro, imprime "[sku]: [name] - $[price]"
// Formatea el precio con exactamente 2 decimales

?>
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de PHP online