Nette DI Контейнер

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

Структуру сервисов, которые должен создавать 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 само обнаружит и передаст благодаря так называемому autowiring, поэтому в конфигурационном файле ничего указывать не нужно. Так что даже если параметры изменятся, вам не придется ничего менять в конфигурации. Контейнер Nette автоматически перегенерируется. Вы можете сосредоточиться исключительно на разработке приложения.

Если мы хотим передавать зависимости с помощью сеттеров, мы используем для этого секцию setup.

Nette DI генерирует непосредственно PHP-код контейнера. Результатом является файл .php, который вы можете открыть и изучить. Благодаря этому вы точно видите, как работает контейнер. Вы также можете отлаживать его в IDE и пошагово выполнять. И главное: сгенерированный PHP чрезвычайно быстр.

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

interface ArticleFactory
{
	function create(): Article;
}

Полный пример вы найдете на GitHub.

Самостоятельное использование

Внедрение библиотеки Nette DI в приложение очень просто. Сначала установим ее с помощью Composer (потому что скачивание zip-архивов тааак устарело):

composer require nette/di

Следующий код создает экземпляр DI-контейнера согласно конфигурации, сохраненной в файле config.neon:

$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:

$controller = $container->getByType(UserController::class);
$controller->someMethod();

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

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

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

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