Metody abstrakcyjne w cechach
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 54 z 91.
Trait mogą udostępniać gotowe do użycia metody, ale czasami potrzebujesz, aby klasa korzystająca z traitu zaimplementowała określoną funkcjonalność. Właśnie wtedy przydają się metody abstrakcyjne w traitach — definiują one kontrakt, który musi spełnić klasa korzystająca z traitu.
Gdy cecha deklaruje metodę abstrakcyjną, każda klasa używająca tej cechy musi ją zaimplementować:
<?php
trait Notifiable {
abstract public function getEmail(): string;
public function sendNotification(string $message): void {
echo "Sending to " . $this->getEmail() . ": $message";
}
}
class User {
use Notifiable;
public function __construct(private string $email) {}
public function getEmail(): string {
return $this->email;
}
}
$user = new User("john@example.com");
$user->sendNotification("Welcome!");
Wynik:
Sending to john@example.com: Welcome!Trait udostępnia metodę sendNotification(), ale wymaga, aby klasa zaimplementowała getEmail(). Tworzy to potężny wzorzec, w którym trait obsługuje wspólną logikę, a szczegóły specyficzne dla klasy deleguje do klasy implementującej.
Jeśli klasa używa cechy bez implementowania metody abstrakcyjnej, PHP zgłasza błąd krytyczny. Dzięki temu cechy mogą bezpiecznie polegać na istnieniu określonych metod, co sprawia, że kod jest bardziej przewidywalny i łatwiejszy w utrzymaniu.
Wyzwanie
ŁatwyStwórzmy system ustalania cen, w którym różne typy produktów obliczają ceny końcowe na różne sposoby, ale korzystają ze wspólnej logiki rabatów dzięki traitowi z metodą abstrakcyjną.
Rozmieścisz kod w trzech plikach:
Discountable.php: Utwórz trait o nazwieDiscountable, który zapewnia funkcjonalność rabatów. Trait powinien zawierać:- Metodę abstrakcyjną
getBasePrice(): float, którą muszą implementować klasy korzystające z tego traitu - Metodę
applyDiscount(int $percent), która oblicza i zwraca cenę po zastosowaniu procentowego rabatu do ceny bazowej - Metodę
getFinalPrice(int $percent), która zwraca sformatowany ciąg znaków:"Final price: $[discounted_price]"z 2 miejscami po przecinku
- Metodę abstrakcyjną
Product.php: Utwórz klasęProduct, która korzysta z traituDiscountable. Dołącz plik z traitem. Użyj promocji konstruktora, aby zdefiniować prywatne$name(string) i prywatne$price(float). Zaimplementuj wymaganą metodęgetBasePrice(), aby zwracała cenę produktu.main.php: Dołącz plik Product. Otrzymasz trzy dane wejściowe: nazwę produktu, cenę i procentowy rabat. Utwórz instancjęProducti wypisz dwa wiersze:- Cenę bazową sformatowaną jako
"Base: $[price]"z 2 miejscami po przecinku - Wynik wywołania
getFinalPrice()z procentowym rabatem
- Cenę bazową sformatowaną jako
Ten wzorzec jest przydatny, ponieważ z traitu Discountable może korzystać dowolna klasa — produkty, usługi, subskrypcje — o ile implementuje getBasePrice(). Trait zapewnia wspólną logikę rabatów, a każda klasa określa, skąd pochodzi jej cena bazowa.
Spróbuj swoich sił
<?php
require_once 'Product.php';
// Odczytaj dane wejściowe
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$discountPercent = intval(trim(fgets(STDIN)));
// TODO: Utwórz instancję Product z nazwą i ceną
// TODO: Wyświetl cenę podstawową w formacie "Base: $[price]" z 2 miejscami po przecinku
// TODO: Wyświetl wynik wywołania getFinalPrice() z procentem rabatu
?>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ów2Przestrzenie 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