В любом приложении объекты имеют тенденцию увеличиваться с ростом приложения. По мере увеличения объектов зависимость между объектами также увеличивается. Зависимость объекта должна быть обработана правильно для успешного приложения.
Как уже говорилось в главе «Компоненты», Symfony предоставляет простой и эффективный компонент DependencyInjection для обработки зависимости объекта. Служебный контейнер — это контейнер объектов с правильно разрешенной зависимостью между ними. Давайте узнаем, как использовать компонент DependencyInjection в этой главе.
Давайте создадим класс Greeter . Цель класса Greeter — приветствовать пользователя, как показано в следующем примере.
$greeter = new Greeter('Hi'); $greeter->greet('Jon'); // print "Hi, Jon"
Полный код класса Greeter выглядит следующим образом.
class Greeter { private $greetingText; public function __construct($greetingText) { $this->greetingText = $greetingText; } public function greet($name) { echo $this->greetingText . ", " . $name . "\r\n"; } }
Теперь давайте добавим класс Greeter в сервисный контейнер. Symfony предоставляет ContainerBuilder для создания нового контейнера. Как только контейнер создан, класс Greeter может быть зарегистрирован в нем с помощью метода register контейнера.
use Symfony\Component\DependencyInjection\ContainerBuilder; $container = new ContainerBuilder(); $container ->register('greeter', 'Greeter') ->addArgument('Hi');
Здесь мы использовали статический аргумент для указания текста приветствия, Привет. Symfony также обеспечивает динамическую настройку параметров. Чтобы использовать динамический параметр, нам нужно выбрать имя и указать его между%, а параметр можно установить с помощью метода setParameter контейнера.
$container = new ContainerBuilder(); $container ->register('greeter', 'Greeter') ->addArgument('%greeter.text%'); $container->setParameter('greeter.text', 'Hi');
Мы зарегистрировали класс Greeter с правильной настройкой. Теперь мы можем попросить контейнер предоставить правильно сконфигурированный объект Greeter, используя метод get контейнера.
$greeter = $container->get('greeter'); $greeter->greet('Jon'); // prints "Hi, Jon"
Мы успешно зарегистрировали класс, добавили его в контейнер, извлекли его из контейнера и использовали. Теперь давайте создадим другой класс User , который использует класс Greeter и посмотрим, как его зарегистрировать.
class User { private $greeter; public $name; public $age; public function setGreeter(\Greeter $greeter) { $this->greeter = $greeter; } public function greet() { $this->greeter->greet($this->name); } }
Класс User получает класс Greeter, используя один из его метода setter, setGreeter . Для этого сценария Symfony предоставляет метод addMethodCall и класс Reference для ссылки на другой класс, как показано в следующем коде.
use Symfony\Component\DependencyInjection\Reference; $container ->register('user', 'User') ->addMethodCall('setGreeter', array(new Reference('greeter')));
Наконец, мы зарегистрировали два класса, Greeter и User, имеющие тесные связи между ними. Теперь мы можем безопасно извлечь объект User с правильно настроенным классом Greeter из контейнера, как показано в следующем коде.
$container->setParameter('greeter.text', 'Hi'); $user = $container->get('user'); $user->name = "Jon"; $user->age = 20; $user->greet(); // Prints "Hi, Jon"
Мы видели, как настроить объект в контейнере, используя сам PHP. Symfony предоставляет и другие механизмы. Это файлы конфигурации XML и YAML. Давайте посмотрим, как настроить контейнер с использованием YAML. Для этого установите компоненты symfony / config и symfony / yaml вместе с компонентами symfony / dependency -jection .
cd /path/to/dir mkdir dependency-injection-example cd dependency-injection-example composer require symfony/dependency-injection composer require symfony/config composer require symfony/yaml
Конфигурация YAML будет записана в отдельном файле services.yml . Конфигурация YAML состоит из двух разделов, параметров и сервисов . Раздел Parameters определяет все обязательные параметры. Раздел Сервисы определяет все объекты. Раздел служб дополнительно разделен на несколько разделов, а именно: класс, аргументы и вызовы . Класс указывает фактический класс. Аргументы определяют аргументы конструктора. Наконец, вызовы определяют методы установки. На другой класс можно ссылаться с помощью символа @, @greeter.
parameters: greeter.text: 'Hello' services: greeter: class: Greeter arguments: ['%greeter.text%'] user: class: User calls: - [setGreeter, ['@greeter']]
Теперь services.yml может быть загружен и настроен с использованием FileLoader и YamlFileLoader, как показано в следующем коде.
use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; $yamlContainer = new ContainerBuilder(); $loader = new YamlFileLoader($yamlContainer, new FileLocator(__DIR__)); $loader->load('services.yml'); $yamlUser = $yamlContainer->get('user'); $yamlUser->name = "Jon"; $yamlUser->age = 25; $yamlUser->greet();
Полный список кодов выглядит следующим образом.
main.php
<?php require __DIR__ . '/vendor/autoload.php'; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; class Greeter { private $greetingText; public function __construct($greetingText) { $this->greetingText = $greetingText; } public function greet($name) { echo $this->greetingText . ", " . $name . "\r\n"; } } class User { private $greeter; public $name; public $age; public function setGreeter(\Greeter $greeter) { $this->greeter = $greeter; } public function greet() { $this->greeter->greet($this->name); } } $container = new ContainerBuilder(); $container ->register('greeter', 'Greeter') ->addArgument('%greeter.text%'); $container ->register('user', 'User') ->addMethodCall('setGreeter', array(new Reference('greeter'))); $container->setParameter('greeter.text', 'Hi'); $greeter = $container->get('greeter'); $greeter->greet('Jon'); $user = $container->get('user'); $user->name = "Jon"; $user->age = 20; $user->greet(); $yamlContainer = new ContainerBuilder(); $loader = new YamlFileLoader($yamlContainer, new FileLocator(__DIR__)); $loader->load('services.yml'); $yamlHello = $yamlContainer->get('greeter'); $yamlHello->greet('Jon'); $yamlUser = $yamlContainer->get('user'); $yamlUser->name = "Jon"; $yamlUser->age = 25; $yamlUser->greet(); ?>
services.yml
parameters: greeter.text: 'Hello' services: greeter: class: Greeter arguments: ['%greeter.text%'] user: class: User calls: - [setGreeter, ['@greeter']]
Веб-фреймворк Symfony широко использует компонент внедрения зависимостей. Все компоненты связаны централизованным сервисным контейнером. Веб-фреймворк Symfony предоставляет контейнер во всем его контроллере через свойство контейнера . Через него мы можем зарегистрировать весь объект, например, регистратор, почтовик и т. Д.
$logger = $this->container->get('logger'); $logger->info('Hi');
Чтобы найти объект, зарегистрированный в контейнере, используйте следующую команду.
cd /path/to/app php bin/console debug:container
В приветственном веб-приложении, созданном в главе по установке, содержится около 200+ объектов.