Menu
Coddy logo textTech

Generatori e iteratori

Fa parte della sezione Programmazione orientata agli oggetti del percorso PHP di Coddy. Lezione 62 di 91.

I generator offrono un modo semplice per creare iteratori senza implementare l'intera interfaccia Iterator. Una funzione generatrice usa yield invece di return per produrre valori uno alla volta, sospendendo l'esecuzione tra un valore e l'altro.

Ecco un generatore di base che produce una sequenza di numeri:

<?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
3

Il vantaggio principale è l'efficienza della memoria. Invece di creare un intero array in memoria, i generatori producono valori su richiesta. Questo è fondamentale quando si lavora con grandi insiemi di dati: un generatore che elabora un milione di record usa la stessa memoria di uno che ne elabora dieci.

I generatori possono anche restituire coppie chiave-valore:

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

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

Output:

admin: Alice
editor: Bob

Per rendere iterabili le tue classi con foreach, implementa l’interfaccia Iterator. Tuttavia, nella maggior parte dei casi, i generatori offrono una soluzione più semplice e con meno codice boilerplate. Sono particolarmente utili nella programmazione orientata agli oggetti quando una classe deve esporre una raccolta di elementi senza caricarli tutti in memoria in una volta sola.

challenge icon

Sfida

Facile

Costruiamo un sistema di inventario dei prodotti che utilizza generatori per scorrere in modo efficiente grandi raccolte senza caricarle tutte in memoria contemporaneamente. Creerai una classe che memorizza i prodotti e fornisce metodi generatori per scorrerli in modi diversi.

Organizzerai il codice in tre file:

  • Product.php: crea una classe Product che rappresenta un articolo in inventario. Usa la promozione del costruttore per definire un $sku pubblico (stringa), un $name pubblico (stringa) e un $price pubblico (float).
  • Inventory.php: crea una classe Inventory che gestisce una raccolta di prodotti e fornisce metodi generatori per scorrerli. Includi il file Product. La classe dovrebbe:
    • Avere una proprietà array privata per memorizzare i prodotti
    • Avere un metodo addProduct(Product $product) che aggiunge un prodotto alla raccolta
    • Avere un metodo generatore allProducts(): Generator che restituisce ogni prodotto uno alla volta
    • Avere un metodo generatore expensiveProducts(float $minPrice): Generator che restituisce solo i prodotti con un prezzo maggiore o uguale al minimo indicato, restituendo coppie chiave-valore in cui la chiave è lo SKU e il valore è il prodotto
  • main.php: includi il file Inventory. Riceverai un input: una soglia di prezzo minimo.

    Crea un Inventory e aggiungi questi tre prodotti:

    • SKU: "A001", nome: "Laptop", prezzo: 999.99
    • SKU: "A002", nome: "Mouse", prezzo: 29.99
    • SKU: "A003", nome: "Monitor", prezzo: 349.99

    Per prima cosa, scorri allProducts() e stampa il nome di ogni prodotto su una riga separata.

    Poi stampa una riga vuota, quindi scorri expensiveProducts() usando la soglia fornita nell'input. Per ogni prodotto costoso, stampa "[sku]: [name] - $[price]" su una riga separata. Formatta il prezzo con esattamente 2 cifre decimali.

Questa sfida mostra come i generatori consentano di scorrere le raccolte in modo lazy: ogni prodotto viene restituito solo quando richiesto, rendendo questo approccio efficiente in termini di memoria per gli inventari di grandi dimensioni. La restituzione di coppie chiave-valore in expensiveProducts() mostra come i generatori possano fornire dati strutturati durante l'iterazione.

Provalo tu

<?php

require_once 'Inventory.php';

// Leggi l'input
$minPrice = floatval(trim(fgets(STDIN)));

// TODO: Crea un'istanza di Inventory

// TODO: Aggiungi tre prodotti:
// SKU: "A001", Nome: "Laptop", Prezzo: 999.99
// SKU: "A002", Nome: "Mouse", Prezzo: 29.99
// SKU: "A003", Nome: "Monitor", Prezzo: 349.99

// TODO: Itera su allProducts() e stampa il nome di ogni prodotto

// TODO: Stampa una riga vuota

// TODO: Itera su expensiveProducts() usando $minPrice
// Per ogni prodotto costoso, stampa "[sku]: [name] - $[price]"
// Formatta il prezzo con esattamente 2 cifre decimali

?>
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore PHP online