Nette DI-контейнер

Nette DI Container – одна из самых интересных частей фреймворка. Он может генерировать скомпилированные DI-контейнеры, которые чрезвычайно быстры и удивительно просты в настройке.

Nette DI – это библиотека, которая предоставляет инструменты для генерации, а также автоматического обновления классов контейнеров. Мы инструктируем его (обычно) с помощью конфигурационных файлов. Контейнер, который мы создали вручную в предыдущем разделе, будет записан в конфигурационном NEON формате следующим образом:

parameters:
	db:
		dsn: 'mysql:'
		user: root
		password: '***'

services:
	- Nette\Database\Connection(%db.dsn%, %db.user%, %db.password%)
	- ArticleFactory
	- UserController

Нотация действительно краткая.

Все зависимости, объявленные в конструкторах ArticleFactory и UserController, автоматически определяются и передаются Nette DI благодаря так называемому автосвязыванию. Таким образом, вы можете сосредоточиться на разработке.

Если вы хотите передавать зависимости с помощью сеттера, мы можем добавить секцию setup в определение сервиса.

Nette DI будет фактически генерировать PHP-код для контейнера. Поэтому он чрезвычайно быстр, программист точно знает, что он делает, и даже может переступать через него. Для больших приложений контейнер может состоять из десятков тысяч строк, и поддерживать что-то подобное вручную, вероятно, уже невозможно.

Nette DI также может генерировать код фабрики на основе интерфейса. Таким образом, вместо класса ArticleFactory вам нужно будет просто создать интерфейс:

interface ArticleFactory
{
	function create(): Article;
}

Вы можете найти полный пример на GitHub.

Использование без фреймворка

Использовать Nette DI в приложении очень просто. Сначала мы установим его с помощью Composer (потому что загрузка zip-файлов уже устарела):

composer require nette/di

Мы сохраним приведенную выше конфигурацию в файле config.neon и создадим контейнер, используя класс Nette\DI\ContainerLoader:

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp');
$class = $loader->load(function($compiler) {
	$compiler->loadConfig(__DIR__ . '/config.neon');
});
$container = new $class;

Контейнер создается только один раз, его код записывается в кэш (каталог __DIR__ . '/temp') и при последующих запросах считывается только оттуда.

Методы getService() или getByType() используются для создания и получения сервисов. Таким образом мы создаем объект UserController:

$database = $container->getByType(UserController::class);
$database->query('...');

Во время разработки полезно включить режим автообновления, при котором контейнер автоматически обновляется при изменении любого класса или файла конфигурации. Просто укажите true в качестве второго аргумента в конструкторе ContainerLoader.

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true);

Использование с Nette Framework

Как мы показали, использование Nette DI не ограничивается приложениями, написанными на Nette Framework, вы можете развернуть его где угодно, используя всего 3 строки кода. Если вы разрабатываете приложения в Nette, конфигурирование и создание контейнера осуществляется с помощью класса Bootstrap.