Generatory i iteratory
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 62 z 91.
Generatory zapewniają prosty sposób tworzenia iteratorów bez implementowania pełnego interfejsu Iterator. Funkcja generatora używa yield zamiast return, aby zwracać wartości pojedynczo, wstrzymując wykonanie między kolejnymi wartościami.
Oto podstawowy generator, który tworzy sekwencję liczb:
<?php
function countTo(int $max): Generator {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (countTo(3) as $number) {
echo "$number\n";
}
Wynik:
1
2
3Kluczową zaletą jest oszczędność pamięci. Zamiast tworzyć całą tablicę w pamięci, generatory wytwarzają wartości na żądanie. Ma to kluczowe znaczenie podczas pracy z dużymi zbiorami danych — generator przetwarzający milion rekordów zużywa tyle samo pamięci co generator przetwarzający dziesięć rekordów.
Generatory mogą również zwracać pary klucz-wartość:
<?php
function userGenerator(): Generator {
yield 'admin' => 'Alice';
yield 'editor' => 'Bob';
}
foreach (userGenerator() as $role => $name) {
echo "$role: $name\n";
}
Wynik:
admin: Alice
editor: BobAby umożliwić iterowanie po własnych klasach za pomocą foreach, zaimplementuj interfejs Iterator. Jednak w większości przypadków generatory oferują prostsze rozwiązanie, wymagające mniej kodu pomocniczego. Są szczególnie przydatne w programowaniu obiektowym, gdy klasa musi udostępniać kolekcję elementów bez jednoczesnego ładowania wszystkiego do pamięci.
Wyzwanie
ŁatwyStwórzmy system zarządzania zapasami produktów, który wykorzystuje generatory do wydajnego iterowania po dużych kolekcjach bez ładowania wszystkiego naraz do pamięci. Utworzysz klasę, która przechowuje produkty i udostępnia metody generatorowe do iterowania po nich na różne sposoby.
Rozmieścisz swój kod w trzech plikach:
Product.php: Utwórz klasęProduct, która reprezentuje produkt w zapasach. Użyj promocji właściwości konstruktora, aby zdefiniować publiczne$sku(string), publiczne$name(string) oraz publiczne$price(float).Inventory.php: Utwórz klasęInventory, która zarządza kolekcją produktów i udostępnia metody generatorowe do iterowania po nich. Dołącz plik Product. Klasa powinna:- Mieć prywatną właściwość typu tablica do przechowywania produktów
- Mieć metodę
addProduct(Product $product), która dodaje produkt do kolekcji - Mieć metodę generatorową
allProducts(): Generator, która zwraca każdy produkt pojedynczo za pomocą yield - Mieć metodę generatorową
expensiveProducts(float $minPrice): Generator, która zwraca tylko produkty o cenie większej lub równej podanej wartości minimalnej, zwracając pary klucz-wartość, gdzie kluczem jest SKU, a wartością produkt
main.php: Dołącz plik Inventory. Otrzymasz jedno wejście: próg ceny minimalnej.Utwórz obiekt
Inventoryi dodaj te trzy produkty:- SKU:
"A001", nazwa:"Laptop", cena:999.99 - SKU:
"A002", nazwa:"Mouse", cena:29.99 - SKU:
"A003", nazwa:"Monitor", cena:349.99
Najpierw iteruj przez
allProducts()i wypisz nazwę każdego produktu w osobnym wierszu.Następnie wypisz pusty wiersz, po czym iteruj przez
expensiveProducts(), używając progu z wejścia. Dla każdego drogiego produktu wypisz"[sku]: [name] - $[price]"w osobnym wierszu. Sformatuj cenę z dokładnością do 2 miejsc po przecinku.- SKU:
To wyzwanie pokazuje, jak generatory umożliwiają leniwe iterowanie po kolekcjach: każdy produkt jest zwracany dopiero na żądanie, dzięki czemu takie podejście jest wydajne pod względem pamięci w przypadku dużych zapasów. Zwracanie par klucz-wartość w expensiveProducts() pokazuje, jak generatory mogą dostarczać uporządkowane dane iteracji.
Spróbuj swoich sił
<?php
require_once 'Inventory.php';
// Odczytaj dane wejściowe
$minPrice = floatval(trim(fgets(STDIN)));
// TODO: Utwórz instancję Inventory
// TODO: Dodaj trzy produkty:
// SKU: "A001", Nazwa: "Laptop", Cena: 999.99
// SKU: "A002", Nazwa: "Mouse", Cena: 29.99
// SKU: "A003", Nazwa: "Monitor", Cena: 349.99
// TODO: Przejdź przez allProducts() i wypisz nazwę każdego produktu
// TODO: Wypisz pustą linię
// TODO: Przejdź przez expensiveProducts(), używając $minPrice
// Dla każdego drogiego produktu wypisz "[sku]: [name] - $[price]"
// Sformatuj cenę z dokładnie 2 miejscami po przecinku
?>Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe $thisMetodyWłaściwościKonstruktor (__construct)Destruktor (__destruct)Powtórka — prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe parent::Przesłanianie metodSłowo kluczowe finalKlasy abstrakcyjnePowtórzenie – hierarchia pracowników7Enkapsulacja
Public, protected, privateModyfikatory dostępu w szczegółachGettery i setteryUkrywanie informacjiPromocja parametrów konstruktora (8.0)Podsumowanie — system ewidencji studentów10Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieWstrzykiwanie zależnościKlasy anonimoweEnumy (PHP 8.1)Włókna (PHP 8.1)Dogłębne omówienie klonowania obiektówGeneratory i iteratory2Przestrzenie nazw i autoloading
Wprowadzenie do przestrzeni nazwSłowo kluczowe useStandard autoloadingu PSR-4Autoloader ComposeraPodsumowanie – uporządkowany projekt5Interfejsy i kontrakty
Wprowadzenie do interfejsówImplementowanie interfejsówImplementowanie wielu interfejsówInterfejs a klasa abstrakcyjnaPodpowiadanie typów za pomocą interfejsówPodsumowanie — kalkulator kształtów8Metody magiczne
Wprowadzenie do metod magicznych__toString i __debugInfo__get, __set, __isset, __unset__call i __callStatic__clone i klonowanie obiektów__serialize i __unserializePodsumowanie — własna kolekcja11System typów i obsługa błędów
Deklaracje typówTypy nullableTypy sumy i przecięciaKlasy wyjątkówNiestandardowa hierarchia wyjątkówTry, Catch, FinallyPodsumowanie — walidator formularzy14Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Właściwości klas
Właściwości instancji a właściwości statyczneStałe w klasachMetody i właściwości statyczneWłaściwości prywatne i chronioneWłaściwości tylko do odczytu (PHP 8.1)Podsumowanie — menedżer kont bankowych6Polimorfizm
Ponowne omówienie nadpisywania metodPolimorfizm za pomocą interfejsówPodpowiedzi typów i typy sumyPóźne wiązanie statycznePodsumowanie — procesor płatności9Cechy
Wprowadzenie do cechKorzystanie z wielu cechRozwiązywanie konfliktów cechMetody abstrakcyjne w cechachCechy a dziedziczenie12Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec StrategyPoćwicz samodzielnie: Kompilator PHP online