Co je DI kontejner?
Dependency injection kontejner (DIC) je třída, která umí instancovat a konfigurovat objekty.
Možná vás to překvapí, ale v mnoha případech nepotřebujete dependency injection kontejner, abyste mohli využívat výhod dependency injection (krátce DI). Vždyť i v úvodní kapitole jsme si na konkrétních příkladech DI ukázali a žádný kontejner nebyl potřeba.
Pokud však potřebujete spravovat velké množství různých objektů s mnoha závislostmi, bude dependency injection container opravdu užitečný. Což je třeba případ webových aplikací postavených na frameworku.
V předchozí kapitole jsme si představili třídy Article
a UserController
. Obě mají nějaké
závislosti, a to databázi a továrnu ArticleFactory
. A pro tyto třídy si nyní vytvoříme kontejner.
Samozřejmě pro tak jednoduchý příklad nemá smysl mít kontejner. Ale vytvoříme ho, abychom si ukázali, jak vypadá a
funguje.
Zde je jednoduchý hardcoded kontejner pro uvedený příklad:
Použití by vypadalo následovně:
Kontejneru se pouze zeptáme na objekt a již nemusíme vědět nic o tom, jak jej vytvořit a jaké má závislosti; to všechno ví kontejner. Závislosti jsou kontejnerem injektovány automaticky. V tom je jeho síla.
Kontejner má zatím zapsané všechny údaje natvrdo. Uděláme tedy další krok a přidáme parametry, aby byl kontejner skutečně užitečný:
Bystří čtenáři si možná všimli jistého problému. Pokaždé, když získám objekt UserController
,
vytvoří se také nová instance ArticleFactory
a databáze. To rozhodně nechceme.
Přidáme proto metodu getService()
, která bude vracet stále stejné instance:
Při prvním volání např. $container->getService('Database')
si nechá od createDatabase()
vytvořit objekt databáze, který uloží do pole $services
a při příštím volání jej rovnou vrátí.
Upravíme i zbytek kontejneru, aby používal getService()
:
Mimochodem, termínem služba se označuje jakýkoliv objekt spravovaný kontejnerem. Proto i ten název metody
getService()
.
Hotovo. Máme plně funkční DI kontejner! A můžeme ho použít:
Jak vidíte, napsat DIC není nic složitého. Za připomenutí stojí, že samotné objekty neví, že je vytváří nějaký kontejner. Tím pádem je možné takto vytvářet jakýkoliv objekt v PHP bez zásahu do jeho zdrojového kódu.
Ruční vytváření a údržba třídy kontejneru se může poměrně rychle stát noční můrou. V další kapitole si proto povíme o Nette DI Containeru, který se umí generovat a aktualizovat téměř sám.