Inject metódusok és attribútumok

Ebben a cikkben a függőségek Nette keretrendszerbeli presenterekbe történő átadásának különböző módjaira összpontosítunk. Összehasonlítjuk az előnyben részesített módszert, amely a konstruktor, más lehetőségekkel, mint például az inject metódusok és attribútumok.

A presenterekre is igaz, hogy a függőségek konstruktoron keresztüli átadása az előnyben részesített út. Ha azonban létrehozol egy közös őst, amelyből a többi presenter öröklődik (pl. BasePresenter), és ennek az ősnek is vannak függőségei, akkor egy problémába ütközünk, amelyet constructor hell-nek nevezünk. Ezt meg lehet kerülni alternatív utakkal, amelyeket az inject metódusok és attribútumok (korábban annotációk) jelentenek.

inject*() metódusok

Ez a függőségátadás setterrel történő formája. Ezeknek a settereknek a neve inject előtaggal kezdődik. A Nette DI az így elnevezett metódusokat automatikusan meghívja rögtön a presenter példányának létrehozása után, és átadja nekik az összes szükséges függőséget. Ezért public-ként kell deklarálni őket.

Az inject*() metódusok tekinthetők a konstruktor egyfajta kiterjesztésének több metódusba. Ennek köszönhetően a BasePresenter más metóduson keresztül veheti át a függőségeket, és a konstruktort szabadon hagyhatja a leszármazottai számára:

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;
	}
}

A presenter tetszőleges számú inject*() metódust tartalmazhat, és mindegyiknek tetszőleges számú paramétere lehet. Kiválóan alkalmasak olyan esetekben is, amikor a presenter traitekből áll össze, és mindegyik saját függőséget igényel.

Inject attribútumok

Ez a property-be történő injektálás formája. Elég megjelölni, hogy mely változókba kell injektálni, és a Nette DI automatikusan átadja a függőségeket rögtön a presenter példányának létrehozása után. Ahhoz, hogy be tudja illeszteni őket, public-ként kell deklarálni őket.

A property-ket attribútummal jelöljük meg: (korábban a /** @inject */ annotációt használták)

use Nette\DI\Attributes\Inject;  // ez a sor fontos

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

Ennek a függőségátadási módnak az előnye a nagyon tömör írásmód volt. Azonban a constructor property promotion megjelenésével egyszerűbbnek tűnik a konstruktor használata.

Másrészt ez a módszer ugyanazoktól a hiányosságoktól szenved, mint a függőségek általános property-kbe történő átadása: nincs ellenőrzésünk a változóban bekövetkező változások felett, és ugyanakkor a változó az osztály nyilvános interfészének részévé válik, ami nem kívánatos.