Учебники

Symfony — Сервисный контейнер

В любом приложении объекты имеют тенденцию увеличиваться с ростом приложения. По мере увеличения объектов зависимость между объектами также увеличивается. Зависимость объекта должна быть обработана правильно для успешного приложения.

Как уже говорилось в главе «Компоненты», 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+ объектов.