Metodi e attributi inject
Questo articolo si concentra sui vari modi di passare le dipendenze ai presenter nel framework Nette.
Confronteremo il metodo preferito, l'iniezione tramite costruttore, con le alternative, cioè i metodi e gli attributi
inject.
Per i presenter, come per le altre classi, il modo preferito di passare le dipendenze è tramite il costruttore. Se
però create un antenato comune dal quale gli altri presenter ereditano (per esempio BasePresenter) e anche questo
antenato richiede delle dipendenze, può nascere un problema noto come inferno dei
costruttori. Lo si può aggirare con metodi alternativi, cioè con i metodi e gli attributi inject (in passato
annotazioni).
Metodi inject*()
È una forma di passaggio delle dipendenze tramite setter. I nomi di questi
setter devono iniziare con il prefisso inject. Nette DI chiama automaticamente i metodi con questo nome subito dopo
aver creato l'istanza del presenter, passando loro tutte le dipendenze necessarie. Devono quindi essere dichiarati pubblici.
I metodi inject*() si possono vedere come estensioni del costruttore, suddivise in più metodi. Questo permette a
BasePresenter di ricevere le proprie dipendenze con un metodo separato, lasciando libero il costruttore per i suoi
discendenti:
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;
}
}
Un presenter può avere un numero qualsiasi di metodi inject*(), e ognuno può accettare un numero qualsiasi di
parametri. Questo approccio si presta bene anche ai casi in cui un presenter è composto da trait e ogni trait richiede le proprie
dipendenze.
Attributi Inject
È una forma di iniezione nelle proprietà. Basta contrassegnare le proprietà da iniettare e Nette DI passerà automaticamente le dipendenze subito dopo aver creato l'istanza del presenter. Perché l'iniezione sia possibile, queste proprietà devono essere dichiarate pubbliche.
Le proprietà si contrassegnano con un attributo: (in passato si usava l'annotazione /** @inject */)
use Nette\DI\Attributes\Inject; // questa riga è importante
class MyPresenter extends Nette\Application\UI\Presenter
{
#[Inject]
public Cache $cache;
}
Il vantaggio di questo modo di passare le dipendenze era la sintassi molto concisa. Con l'introduzione della constructor property promotion, però, usare il costruttore appare spesso più semplice.
Al contrario, questo metodo soffre degli stessi difetti dell'iniezione nelle proprietà in generale: ci manca il controllo sulle modifiche della variabile e la variabile entra a far parte dell'interfaccia pubblica della classe, cosa in generale indesiderabile.