Co to jest kontener DI?
Dependency injection container (DIC) to klasa, która może instancjonować i konfigurować obiekty.
Może cię to zaskoczyć, ale w wielu przypadkach nie potrzebujesz kontenera wtrysku zależności, aby skorzystać z wtrysku zależności (w skrócie DI). Przecież nawet w poprzednim rozdziale pokazywaliśmy konkretne przykłady DI i żaden kontener nie był potrzebny.
Jeśli jednak musisz zarządzać dużą liczbą różnych obiektów z wieloma zależnościami, kontener wtrysku zależności będzie naprawdę przydatny. Co ma miejsce np. w przypadku aplikacji internetowych zbudowanych na frameworku.
W poprzednim rozdziale przedstawiliśmy klasy Article
i UserController
. Obie mają pewne
zależności, a mianowicie bazę danych i fabrykę ArticleFactory
. I dla tych klas stworzymy teraz kontener.
Oczywiście dla tak prostego przykładu posiadanie kontenera nie ma sensu. Ale stworzymy jeden, aby pokazać jak to wygląda
i działa.
Oto prosty kontener hardcoded dla tego przykładu:
Użycie wyglądałoby tak:
Po prostu pytamy kontener o obiekt i nie musimy nic wiedzieć o tym, jak go stworzyć i jakie są jego zależności; kontener wie to wszystko. Zależności są wstrzykiwane automatycznie przez kontener. To jest jego moc.
Do tej pory kontener zapisywał wszystkie dane na górze. Robimy więc kolejny krok i dodajemy parametry, aby kontener był naprawdę użyteczny:
Uważni czytelnicy mogli zauważyć pewien problem. Za każdym razem, gdy otrzymuję obiekt UserController
,
tworzona jest również nowa instancja ArticleFactory
i baza danych. Z pewnością tego nie chcemy.
Dodamy więc metodę getService()
, która będzie zwracała w kółko te same instancje:
Przy pierwszym wywołaniu np. $container->getService('Database')
zleci createDatabase()
stworzenie
obiektu bazy danych, który zapisze w tablicy $services
i zwróci go bezpośrednio przy kolejnym wywołaniu.
Modyfikujemy też resztę kontenera, aby korzystał z getService()
:
Przy okazji, termin usługa odnosi się do dowolnego obiektu zarządzanego przez kontener. Stąd nazwa metody
getService()
.
Zrobione. Mamy w pełni funkcjonalny kontener DI! I możemy z niego korzystać:
Jak widać, napisanie DIC nie jest trudne. Warto pamiętać, że same obiekty nie wiedzą, że tworzy je kontener. Można więc w ten sposób stworzyć dowolny obiekt w PHP bez ingerencji w jego kod źródłowy.
Ręczne tworzenie i utrzymywanie klasy kontenera może dość szybko stać się koszmarem. Dlatego w następnym rozdziale opowiemy o kontenerze Nette DI Container, który może generować i aktualizować się niemal samodzielnie.