Методы и атрибуты 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 кажется проще использовать конструктор.
Напротив, этот способ страдает теми же недостатками, что и передача зависимости в свойства в целом: у нас нет контроля над изменениями в переменной, и в то же время переменная становится частью публичного интерфейса класса, что нежелательно.