Metody i atrybuty inject
Ten artykuł skupia się na różnych sposobach przekazywania zależności do presenterów we frameworku Nette.
Porównamy preferowany sposób, czyli wstrzykiwanie przez konstruktor, z alternatywami w postaci metod i atrybutów
inject.
W przypadku presenterów, podobnie jak w innych klasach, preferowanym sposobem przekazywania zależności jest konstruktor.
Jeśli jednak tworzysz wspólnego przodka, po którym dziedziczą pozostałe presentery (np. BasePresenter), i ten
przodek również potrzebuje zależności, może pojawić się problem zwany constructor hell. Da się
go obejść za pomocą alternatywnych sposobów, czyli metod i atrybutów inject (dawniej adnotacji).
Metody inject*()
Jest to forma przekazywania zależności przez settery. Nazwy tych
setterów muszą zaczynać się od przedrostka inject. Nette DI wywołuje tak nazwane metody automatycznie zaraz po
utworzeniu instancji presentera i przekazuje im wszystkie potrzebne zależności. Dlatego muszą być zadeklarowane jako
public.
Metody inject*() można traktować jako rozszerzenie konstruktora rozbite na kilka metod. Dzięki temu
BasePresenter może przyjąć zależności osobną metodą i pozostawić konstruktor do dyspozycji swoim
potomkom:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
private Foo $foo;
public function injectBase(Foo $foo): void
{
$this->foo = $foo;
}
}
class MyPresenter extends BasePresenter
{
private Bar $bar;
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
Presenter może mieć dowolną liczbę metod inject*(), a każda z nich może przyjmować dowolną liczbę
parametrów. Ten sposób świetnie sprawdza się także wtedy, gdy presenter jest składany z traitów, a każdy trait wymaga własnych
zależności.
Atrybuty Inject
Jest to forma wstrzykiwania do właściwości. Wystarczy oznaczyć właściwości, które mają zostać wstrzyknięte, a Nette DI przekaże zależności automatycznie zaraz po utworzeniu instancji presentera. Aby wstrzyknięcie było możliwe, właściwości te muszą być zadeklarowane jako public.
Właściwości oznaczamy atrybutem: (wcześniej używano adnotacji /** @inject */)
use Nette\DI\Attributes\Inject; // ta linia jest ważna
class MyPresenter extends Nette\Application\UI\Presenter
{
#[Inject]
public Cache $cache;
}
Zaletą tego sposobu przekazywania zależności była bardzo zwięzła składnia. Odkąd jednak istnieje constructor property promotion, użycie konstruktora często wydaje się prostsze.
Z drugiej strony ten sposób cierpi na te same wady co wstrzykiwanie do właściwości w ogóle: nie mamy kontroli nad zmianami zmiennej, a sama zmienna staje się częścią publicznego interfejsu klasy, co jest generalnie niepożądane.