Контейнер Nette DI

Контейнерът Nette DI е една от най-интересните части на рамката. Той може да генерира компилирани контейнери 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 благодарение на така нареченото автоматично свързване. По този начин можете да се съсредоточите върху развитието. So even if the parameters change, you don't need to change anything in the configuration. Nette will automatically regenerate the container. You can concentrate there purely on application development.

Ако искате да предадете зависимостите чрез setter, можем да добавим раздел 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.