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.