Generatoren & Iteratoren
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 62 von 91.
Generatoren bieten eine einfache Möglichkeit, Iteratoren zu erstellen, ohne das vollständige Iterator-Interface zu implementieren. Eine Generator-Funktion verwendet yield anstelle von return, um Werte nacheinander zu erzeugen, wobei die Ausführung zwischen den einzelnen Werten angehalten wird.
Hier ist ein einfacher Generator, der eine Zahlenfolge erzeugt:
<?php
function countTo(int $max): Generator {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (countTo(3) as $number) {
echo "$number\n";
}
Ausgabe:
1
2
3Der entscheidende Vorteil ist die Speichereffizienz. Anstatt ein gesamtes Array im Speicher aufzubauen, erzeugen Generatoren Werte nach Bedarf. Dies ist entscheidend bei der Arbeit mit großen Datensätzen – ein Generator, der eine Million Datensätze verarbeitet, verbraucht denselben Speicher wie einer, der zehn verarbeitet.
Generatoren können auch Schlüssel-Wert-Paare liefern:
<?php
function userGenerator(): Generator {
yield 'admin' => 'Alice';
yield 'editor' => 'Bob';
}
foreach (userGenerator() as $role => $name) {
echo "$role: $name\n";
}
Ausgabe:
admin: Alice
editor: BobUm Ihre eigenen Klassen mit foreach iterierbar zu machen, implementieren Sie das Iterator-Interface. In den meisten Fällen bieten Generatoren jedoch eine sauberere Lösung mit weniger Boilerplate-Code. Sie sind besonders nützlich in der OOP, wenn eine Klasse eine Sammlung von Elementen bereitstellen muss, ohne alles auf einmal in den Speicher zu laden.
Aufgabe
EinfachLassen Sie uns ein Produktinventarsystem aufbauen, das Generatoren verwendet, um effizient durch große Sammlungen zu iterieren, ohne alles auf einmal in den Speicher zu laden. Sie werden eine Klasse erstellen, die Produkte speichert und Generator-Methoden bereitstellt, um auf verschiedene Arten durch sie zu iterieren.
Sie werden Ihren Code über drei Dateien organisieren:
Product.php— Erstellen Sie eineProduct-Klasse, die einen Artikel im Inventar darstellt. Verwenden Sie Constructor Promotion, um ein öffentliches$sku(string), ein öffentliches$name(string) und ein öffentliches$price(float) zu definieren.Inventory.php— Erstellen Sie eineInventory-Klasse, die eine Sammlung von Produkten verwaltet und Generator-Methoden bereitstellt, um durch diese zu iterieren. Binden Sie die Product-Datei ein. Die Klasse sollte:- Eine private Array-Eigenschaft haben, um Produkte zu speichern
- Eine Methode
addProduct(Product $product)haben, die ein Produkt zur Sammlung hinzufügt - Eine Generator-Methode
allProducts(): Generatorhaben, die jedes Produkt einzeln nacheinander ausgibt (yield) - Eine Generator-Methode
expensiveProducts(float $minPrice): Generatorhaben, die nur Produkte mit einem Preis größer oder gleich dem angegebenen Minimum ausgibt, wobei Key-Value-Paare ausgegeben werden, bei denen der Key die SKU und der Value das Produkt ist
main.php— Binden Sie die Inventory-Datei ein. Sie erhalten eine Eingabe: einen Mindestpreisschwellenwert.Erstellen Sie ein
Inventoryund fügen Sie diese drei Produkte hinzu:- SKU:
"A001", Name:"Laptop", Price:999.99 - SKU:
"A002", Name:"Mouse", Price:29.99 - SKU:
"A003", Name:"Monitor", Price:349.99
Iterieren Sie zuerst durch
allProducts()und geben Sie den Namen jedes Produkts in einer eigenen Zeile aus.Geben Sie dann eine Leerzeile aus, gefolgt von der Iteration durch
expensiveProducts()unter Verwendung des eingegebenen Schwellenwerts. Geben Sie für jedes teure Produkt"[sku]: [name] - $[price]"in einer eigenen Zeile aus. Formatieren Sie den Preis mit genau 2 Dezimalstellen.- SKU:
Diese Herausforderung zeigt, wie Generatoren es Ihnen ermöglichen, Sammlungen verzögert (lazy) zu durchlaufen — jedes Produkt wird erst dann ausgegeben, wenn es angefordert wird, was diesen Ansatz für große Inventare speichereffizient macht. Die Key-Value-Ausgabe in expensiveProducts() zeigt, wie Generatoren strukturierte Iterationsdaten bereitstellen können.
Spickzettel
Generatoren bieten eine speichereffiziente Möglichkeit, Iteratoren zu erstellen, indem sie yield anstelle von return verwenden. Sie erzeugen Werte nacheinander und unterbrechen die Ausführung zwischen den einzelnen Werten.
Grundlegende Generator-Funktion:
<?php
function countTo(int $max): Generator {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (countTo(3) as $number) {
echo "$number\n";
}
Generatoren können Schlüssel-Wert-Paare liefern:
<?php
function userGenerator(): Generator {
yield 'admin' => 'Alice';
yield 'editor' => 'Bob';
}
foreach (userGenerator() as $role => $name) {
echo "$role: $name\n";
}
Der Hauptvorteil ist die Speichereffizienz – Generatoren erzeugen Werte bei Bedarf, anstatt ganze Arrays im Speicher aufzubauen. Dies ist besonders nützlich bei der Arbeit mit großen Datensätzen oder Sammlungen in OOP-Kontexten.
Probier es selbst
<?php
require_once 'Inventory.php';
// Eingabe lesen
$minPrice = floatval(trim(fgets(STDIN)));
// TODO: Eine Inventory-Instanz erstellen
// TODO: Drei Produkte hinzufügen:
// SKU: "A001", Name: "Laptop", Preis: 999.99
// SKU: "A002", Name: "Mouse", Preis: 29.99
// SKU: "A003", Name: "Monitor", Preis: 349.99
// TODO: Durch allProducts() iterieren und den Namen jedes Produkts ausgeben
// TODO: Eine Leerzeile ausgeben
// TODO: Durch expensiveProducts() unter Verwendung von $minPrice iterieren
// Für jedes teure Produkt "[sku]: [name] - $[price]" ausgeben
// Preis mit genau 2 Dezimalstellen formatieren
?>Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas $this-SchlüsselwortMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick - Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDas parent:: SchlüsselwortMethoden überschreibenDas final SchlüsselwortAbstrakte KlassenZusammenfassung – Mitarbeiter-Hierarchie7Kapselung
Public, Protected, PrivateZugriffsmodifikatoren im DetailGetter und SetterInformation HidingConstructor Promotion (8.0)Zusammenfassung – Studentenverwaltungssystem10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objekt-Klonen im DetailGeneratoren & Iteratoren2Namensräume & Autoloading
Einführung in NamensräumeDas use-SchlüsselwortPSR-4 Autoloading-StandardComposer AutoloaderZusammenfassung – Organisiertes Projekt5Interfaces & Verträge
Einführung in InterfacesInterfaces implementierenMehrfache Interface-ImplementierungInterface vs. Abstrakte KlasseType Hinting mit InterfacesZusammenfassung – Formen-Rechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objekt-Klonen__serialize & __unserializeZusammenfassung - Eigene Collection11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenEigene Exception-HierarchieTry, Catch, FinallyZusammenfassung - Formular-Validator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klasseneigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenReadonly-Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphismus
Method Overriding erneut betrachtetPolymorphismus über InterfacesType Hinting & Union TypesLate Static BindingZusammenfassung – Payment Processor9Traits
Einführung in TraitsVerwendung mehrerer TraitsKonfliktlösung bei TraitsAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung