Nette Documentation Preview

syntax
Методы и атрибуты inject
************************

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

И для презентеров действует правило, что передача зависимостей с помощью [конструктора |dependency-injection:passing-dependencies#Передача через конструктор] является предпочтительным путем. Однако, если вы создаете общего предка, от которого наследуются другие презентеры (например, `BasePresenter`), и этот предок также имеет зависимости, возникает проблема, которую мы называем [constructor hell |dependency-injection:passing-dependencies#Ад конструкторов]. Ее можно обойти с помощью альтернативных путей, которые представляют собой методы и атрибуты (ранее аннотации) `inject`.


Методы `inject*()`
==================

Это форма передачи зависимости [сеттером |dependency-injection:passing-dependencies#Передача сеттером]. Название этих сеттеров начинается с префикса `inject`. Nette DI автоматически вызывает методы с таким названием сразу после создания экземпляра презентера и передает им все необходимые зависимости. Поэтому они должны быть объявлены как public.

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

```php
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*()`, и каждый может иметь любое количество параметров. Они отлично подходят также в случаях, когда презентер [составлен из трейтов |presenter-traits], и каждый из них требует свою собственную зависимость.


Атрибуты `Inject`
=================

Это форма [инъекции в свойство |dependency-injection:passing-dependencies#Установка переменной]. Достаточно отметить, в какие свойства нужно инжектировать, и Nette DI автоматически передаст зависимости сразу после создания экземпляра презентера. Чтобы он мог их вставить, необходимо объявить их как public.

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

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

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

Преимуществом этого способа передачи зависимостей была очень лаконичная форма записи. Однако с появлением [constructor property promotion |https://blog.nette.org/ru/php-8-0-complete-overview-of-news#toc-constructor-property-promotion] кажется проще использовать конструктор.

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


{{sitename: Best Practices}}

Методы и атрибуты inject

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

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

Методы 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;
}

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

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