Metode in atributi inject

V tem članku se bomo osredotočili na različne načine posredovanja odvisnosti v presenterje v ogrodju Nette. Primerjali bomo prednostni način, ki je konstruktor, z drugimi možnostmi, kot so metode in atributi inject.

Tudi za presenterje velja, da je posredovanje odvisnosti s pomočjo konstruktorja prednostna pot. Če pa ustvarjate skupnega prednika, od katerega dedujejo drugi presenterji (npr. BasePresenter), in ta prednik ima tudi odvisnosti, nastane problem, ki mu pravimo constructor hell. Temu se lahko izognemo z alternativnimi potmi, ki jih predstavljajo metode in atributi (anotacije) inject.

Metode inject*()

Gre za obliko posredovanja odvisnosti s setterjem. Ime teh setterjev se začne s predpono inject. Nette DI tako poimenovane metode samodejno pokliče takoj po ustvarjanju instance presenterja in jim posreduje vse zahtevane odvisnosti. Zato morajo biti deklarirane kot public.

Metode inject*() lahko štejemo za nekakšno razširitev konstruktorja v več metod. Zahvaljujoč temu lahko BasePresenter prevzame odvisnosti prek druge metode in pusti konstruktor prost za svoje potomce:

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 lahko vsebuje poljubno število metod inject*() in vsaka lahko ima poljubno število parametrov. Odlično se obnesejo tudi v primerih, ko je presenter sestavljen iz lastnosti (trait) in vsaka od njih zahteva svojo odvisnost.

Atributi Inject

Gre za obliko injiciranja v lastnost. Dovolj je označiti, v katere spremenljivke naj se injicira, in Nette DI samodejno posreduje odvisnosti takoj po ustvarjanju instance presenterja. Da jih lahko vstavi, jih je treba deklarirati kot public.

Lastnosti označimo z atributom: (prej se je uporabljala anotacija /** @inject */)

use Nette\DI\Attributes\Inject;  // ta vrstica je pomembna

class MyPresenter extends Nette\Application\UI\Presenter
{
	#[Inject]
	public Cache $cache;
}

Prednost tega načina posredovanja odvisnosti je bila zelo varčna oblika zapisa. Vendar pa se z uvedbo constructor property promotion zdi lažje uporabiti konstruktor.

Nasprotno pa ta način trpi za enakimi pomanjkljivostmi kot posredovanje odvisnosti v lastnosti (properties) na splošno: nimamo nadzora nad spremembami v spremenljivki in hkrati spremenljivka postane del javnega vmesnika razreda, kar je nezaželeno.