Методы и атрибуты инъекции

В этой статье мы рассмотрим различные способы передачи зависимостей презентаторам во фреймворке Nette. Мы сравним предпочтительный метод, которым является конструктор, с другими вариантами, такими как методы inject и атрибуты.

Для ведущих также передача зависимостей с помощью конструктора является предпочтительным способом. Однако если вы создаете общего предка, от которого наследуют другие презентаторы (например, BasePresenter), и этот предок также имеет зависимости, возникает проблема, которую мы называем адом конструктора. Ее можно обойти с помощью альтернативных методов, которые включают в себя методы инъекции и атрибуты (аннотации).

inject*() Методы

Это форма передачи зависимостей с помощью сеттеров. Имена этих сеттеров начинаются с префикса inject. Nette DI автоматически вызывает такие именованные методы сразу после создания экземпляра ведущего и передает им все необходимые зависимости. Поэтому они должны быть объявлены как public.

inject*() Методы можно рассматривать как своего рода расширение конструктора на несколько методов. Благодаря этому BasePresenter может принимать зависимости через другой метод и оставлять конструктор свободным для его потомков:

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

Ведущий может содержать любое количество методов inject*(), и каждый из них может иметь любое количество параметров. Это также отлично подходит для случаев, когда ведущий состоит из признаков, и каждый из них требует своей собственной зависимости.

Inject Атрибуты

Это форма инъекции в свойства. Достаточно указать, какие свойства должны быть инжектированы, и Nette DI автоматически передает зависимости сразу после создания экземпляра ведущего. Для инъекции необходимо объявить их как public.

Свойства помечаются атрибутом: (ранее использовалась аннотация /** @inject */)

use Nette\DI\Attributes\Inject; // эта строка важна

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

Преимуществом этого метода передачи зависимостей была очень экономичная форма нотации. Однако, с введением продвижения свойств конструктора, использование конструктора кажется более простым.

С другой стороны, этот метод страдает теми же недостатками, что и передача зависимостей в свойства в целом: у нас нет контроля над изменениями переменной, и в то же время переменная становится частью публичного интерфейса класса, что нежелательно.