Inject-Methoden und -Attribute

Dieser Artikel widmet sich den verschiedenen Wegen, Abhängigkeiten an Presenter im Nette Framework zu übergeben. Wir vergleichen den bevorzugten Weg, den Konstruktor, mit weiteren Möglichkeiten wie den inject-Methoden und -Attributen.

Auch für Presenter gilt, dass die Übergabe von Abhängigkeiten über den Konstruktor der bevorzugte Weg ist. Wenn Sie aber einen gemeinsamen Vorfahren erstellen, von dem die übrigen Presenter erben (z. B. BasePresenter), und dieser Vorfahre ebenfalls Abhängigkeiten hat, entsteht ein Problem, das wir Constructor Hell nennen. Umgehen lässt es sich mit alternativen Wegen, nämlich den Inject-Methoden und -Attributen (früher Annotationen).

inject*()-Methoden

Dabei handelt es sich um eine Form der Abhängigkeitsübergabe per Setter. Die Namen dieser Setter beginnen mit dem Präfix inject. So benannte Methoden ruft Nette DI automatisch unmittelbar nach dem Erzeugen der Presenter-Instanz auf und übergibt ihnen alle geforderten Abhängigkeiten. Sie müssen deshalb als public deklariert sein.

Die inject*()-Methoden lassen sich als eine Art Erweiterung des Konstruktors auf mehrere Methoden verstehen. Dadurch kann der BasePresenter seine Abhängigkeiten über eine eigene Methode entgegennehmen und den Konstruktor für seine Nachkommen frei lassen:

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

Ein Presenter kann beliebig viele inject*()-Methoden enthalten, und jede kann beliebig viele Parameter haben. Hervorragend eignet sich dieser Ansatz auch für Fälle, in denen ein Presenter aus Traits zusammengesetzt ist und jedes Trait eigene Abhängigkeiten verlangt.

Inject-Attribute

Dabei handelt es sich um eine Form der Injektion in Properties. Es genügt, die Properties zu kennzeichnen, in die injiziert werden soll, und Nette DI übergibt die Abhängigkeiten automatisch unmittelbar nach dem Erzeugen der Presenter-Instanz. Damit sie eingesetzt werden können, müssen diese Properties als public deklariert sein.

Die Properties kennzeichnen wir mit einem Attribut: (früher wurde die Annotation /** @inject */ verwendet)

use Nette\DI\Attributes\Inject;  // diese Zeile ist wichtig

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

Der Vorteil dieser Art der Abhängigkeitsübergabe war die sehr sparsame Schreibweise. Mit der Einführung von Constructor Property Promotion erscheint es jedoch einfacher, den Konstruktor zu verwenden.

Umgekehrt leidet dieser Weg an denselben Nachteilen wie die Übergabe von Abhängigkeiten in Properties allgemein: Wir haben keine Kontrolle über Änderungen der Variablen, und die Variable wird Teil der öffentlichen Schnittstelle der Klasse, was unerwünscht ist.