Předávání závislostí
Argumenty, nebo v terminologii DI „závislosti“, lze do tříd předávat těmito hlavními způsoby:
- předávání konstruktorem
- předávání metodou (tzv. setterem)
- nastavením proměnné
- metodou, anotací či atributem inject
První tři způsoby platí obecně ve všech objektově orientovaných jazycích, čtvrtý je specifický pro presentery v Nette, takže o něm pojednává samostatná kapitola. Nyní si jednotlivé možnosti přiblížíme a ukážeme na konkrétních případech.
Předávání konstruktorem
Závislosti jsou předávány v okamžiku vytváření objektu jako argumenty konstruktoru:
class MyService
{
/** @var Cache */
private $cache;
public function __construct(Cache $service)
{
$this->cache = $service;
}
}
$service = new MyService($cache);
Tato forma je vhodná pro povinné závislosti, které třída nezbytně potřebuje ke své funkci, neboť bez nich nepůjde instanci vytvořit.
Předávání setterem
Závislosti jsou předávány voláním metody, která je uloží do privátní proměnné. Obvyklou konvencí pojmenování
těchto metod je tvar set*()
, proto se jim říká settery.
class MyService
{
/** @var Cache */
private $cache;
public function setCache(Cache $service)
{
$this->cache = $service;
}
}
$service = new MyService;
$service->setCache($cache);
Tento způsob je vhodný pro nepovinné závislosti, které nejsou pro funkci třídy nezbytné, neboť není garantováno, že objekt závislost skutečně dostane (tj. že uživatel metodu zavolá).
Zároveň tento způsob připouští volat setter opakovaně a závislost tak měnit. Pokud to není žádoucí, přidáme do metody kontrolu.
class MyService
{
/** @var Cache */
private $cache;
public function setCache(Cache $service)
{
if ($this->cache) {
throw new RuntimeException('The dependency has already been set');
}
$this->cache = $service;
}
}
Volání setteru definujeme v konfiraci DI kontejneru v sekci setup. I tady se využívá automatického předávání závislostí pomocí autowiringu:
services:
-
create: MyService
setup:
- setCache
Nastavením proměnné
Závislosti jsou předávány zapsáním přímo do členské proměnné:
class MyService
{
/** @var Cache */
public $cache;
}
$service = new MyService;
$service->cache = $cache;
Tento způsob se považuje za nevhodný, protože členská proměnná musí být deklarována jako public
.
A tudíž nemáme kontrolu nad tím, že předaná závislost bude skutečně daného typu a přicházíme o možnost reagovat
na nově přiřazenou závislost vlastním kódem, například zabránit následné změně. Zároveň se proměnná stává
součástí veřejného rozhraní třídy, což nemusí být žádoucí.
Nastavení proměnné definujeme v konfiraci DI kontejneru v sekci setup:
services:
-
create: MyService
setup:
- $cache = @\Cache
Jaký způsob zvolit?
- konstruktor je vhodný pro povinné závislosti, které třída nezbytně potřebuje ke své funkci
- setter je naopak vhodný pro nepovinné závislosti, nebo závislosti, které lze mít možnost dále měnit
- veřejné proměnné vhodné nejsou