Menu
Coddy logo textTech

Wstrzykiwanie zależności

Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 57 z 91.

W poprzedniej lekcji zobaczyłeś, jak kompozycja pozwala obiektowi Car zawierać obiekt Engine. Jednak tworzenie zależności wewnątrz klasy ma pewien problem — sprawia, że kod jest sztywny i trudny do testowania. Wstrzykiwanie zależności rozwiązuje ten problem, przekazując zależności z zewnątrz zamiast tworzyć je wewnątrz klasy.

Porównaj te dwa podejścia:

<?php
// Bez DI - zależność tworzona wewnątrz
class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine(); // Ściśle powiązane
    }
}

// Z DI - zależność przekazywana z zewnątrz
class Car {
    public function __construct(private Engine $engine) {}
}

$engine = new Engine();
$car = new Car($engine); // Wstrzyknięte z zewnątrz

Drugie podejście to wstrzykiwanie zależności. Car nie tworzy własnego silnika — otrzymuje go. Ta prosta zmiana przynosi wiele korzyści: możesz przekazywać różne typy silników, podmieniać implementacje na potrzeby testów, a klasa staje się bardziej elastyczna.

Aby uzyskać jeszcze większą elastyczność, wstrzykuj interfejsy zamiast konkretnych klas:

<?php
interface EngineInterface {
    public function start(): string;
}

class Car {
    public function __construct(private EngineInterface $engine) {}
    
    public function start(): string {
        return $this->engine->start();
    }
}

Teraz Car współpracuje z każdą klasą implementującą EngineInterface — silnikiem spalinowym, elektrycznym lub atrapą używaną do testów. To rozdzielenie zależności sprawia, że wstrzykiwanie zależności jest podstawą tworzenia łatwych w utrzymaniu i testowaniu aplikacji PHP.

challenge icon

Wyzwanie

Łatwy

Stwórzmy system powiadomień, który pokazuje siłę wstrzykiwania zależności. Zamiast na sztywno określać sposób wysyłania wiadomości, stworzysz elastyczny system, w którym metodę dostarczania można łatwo zmienić.

Rozmieścisz kod w czterech plikach:

  • MessageSenderInterface.php: Zdefiniuj interfejs o nazwie MessageSenderInterface z jedną metodą send(string $recipient, string $message): string. Ten interfejs określa kontrakt, którego musi przestrzegać każdy nadawca wiadomości.
  • EmailSender.php: Utwórz klasę EmailSender, która implementuje MessageSenderInterface. Dołącz plik interfejsu. Metoda send() powinna zwracać "Email to [recipient]: [message]".
  • NotificationService.php: Utwórz klasę NotificationService, która otrzymuje swoją zależność przez konstruktor. Dołącz plik interfejsu. Klasa powinna:
    • Przyjmować MessageSenderInterface w konstruktorze, używając promocji właściwości konstruktora
    • Mieć metodę notify(string $recipient, string $message), która deleguje działanie do wstrzykniętego nadawcy i zwraca wynik
    Zwróć uwagę, że NotificationService zależy od interfejsu, a nie konkretnej klasy. Oznacza to, że możesz wstrzyknąć dowolnego nadawcę implementującego ten interfejs bez zmieniania usługi.
  • main.php: Dołącz pliki EmailSender i NotificationService. Otrzymasz dwa dane wejściowe: odbiorcę i wiadomość. Utwórz obiekt EmailSender, wstrzyknij go do obiektu NotificationService, a następnie wywołaj notify() i wypisz wynik.

Ten wzorzec zapewnia elastyczność NotificationService. Działa z dowolnym wstrzykniętym nadawcą, niezależnie od tego, czy jest to poczta e-mail, SMS, czy coś, czego jeszcze nie utworzyłeś. Usługa nie tworzy własnych zależności — otrzymuje je z zewnątrz.

Spróbuj swoich sił

<?php
require_once 'EmailSender.php';
require_once 'NotificationService.php';

// Odczytaj dane wejściowe
$recipient = trim(fgets(STDIN));
$message = trim(fgets(STDIN));

// TODO: Utwórz instancję EmailSender
// TODO: Przekaż ją do NotificationService
// TODO: Wywołaj notify() i wypisz wynik

?>
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator PHP online