Métodos e atributos inject

Neste artigo, focaremos nas diferentes maneiras de passar dependências para presenters no framework Nette. Compararemos a forma preferida, que é o construtor, com outras opções, como métodos e atributos inject.

Também para presenters, passar dependências usando o construtor é o caminho preferido. No entanto, se você criar um ancestral comum do qual outros presenters herdam (por exemplo, BasePresenter), e este ancestral também tiver dependências, ocorrerá um problema que chamamos de constructor hell. Isso pode ser contornado usando caminhos alternativos, que são os métodos e atributos (anotações) inject.

Métodos inject*()

É uma forma de passar dependências por setter. O nome desses setters começa com o prefixo inject. O Nette DI chama automaticamente métodos com esse nome logo após a criação da instância do presenter e passa a eles todas as dependências necessárias. Portanto, eles devem ser declarados como public.

Os métodos inject*() podem ser considerados como uma extensão do construtor em vários métodos. Graças a isso, o BasePresenter pode receber dependências através de outro método e deixar o construtor livre para seus descendentes:

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

Um presenter pode conter qualquer número de métodos inject*() e cada um pode ter qualquer número de parâmetros. Eles também são ótimos em casos onde o presenter é composto por traits e cada um deles requer sua própria dependência.

Atributos Inject

É uma forma de injeção na propriedade. Basta marcar em quais propriedades injetar, e o Nette DI passa automaticamente as dependências logo após a criação da instância do presenter. Para poder inseri-las, é necessário declará-las como public.

Marcamos as propriedades com um atributo: (anteriormente, usava-se a anotação /** @inject */)

use Nette\DI\Attributes\Inject;  // esta linha é importante

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

A vantagem dessa forma de passar dependências era a forma de escrita muito concisa. No entanto, com a chegada da promoção de propriedades do construtor, parece mais fácil usar o construtor.

Por outro lado, essa forma sofre das mesmas desvantagens que a passagem de dependências para propriedades em geral: não temos controle sobre as alterações na variável e, ao mesmo tempo, a variável se torna parte da interface pública da classe, o que é indesejável.