Symfony服务容器


在任何应用程序中,对象随着应用程序的增长而增加。随着对象的增加,对象之间的依赖关系也会增加。对于成功的应用程序,需要正确处理对象依赖性。

正如“组件”一章中所讨论的,Symfony提供了一个简单高效的组件, DependencyInjection 来处理对象依赖。服务容器是具有正确解决它们之间依赖关系的对象的容器。让我们学习如何在本章中使用DependencyInjection组件。

让我们创建一个 绿色 课程。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类可以使用容器的注册方法注册到它。

use Symfony\Component\DependencyInjection\ContainerBuilder;
$container = new ContainerBuilder();
$container
   ->register('greeter', 'Greeter')
   ->addArgument('Hi');

在这里,我们使用静态参数来指定问候语文本Hi。Symfony也提供了一个动态的参数设置。要使用动态参数,我们需要选择一个名称并在%之间指定它,并且可以使用容器的 setParameter 方法设置该参数。

$container = new ContainerBuilder();
$container
   ->register('greeter', 'Greeter')
   ->addArgument('%greeter.text%');  
$container->setParameter('greeter.text', 'Hi');

我们已经通过适当的设置注册了Greeter课程。现在,我们可以让容器使用容器 get 方法提供一个正确配置的Greeter对象。

$greeter = $container->get('greeter');
$greeter->greet('Jon'); // prints "Hi, Jon"

我们已成功注册了一门课,Greeter放入容器中,从容器中取出并使用它。现在,让我们创建另一个类 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类使用setter方法 setGreeter 获取 Greeter 类。对于这种情况,Symfony提供了一个方法 addMethodCall 和一个类 Reference, 以引用另一个类,如下面的代码所示。 **

use  Symfony\Component\DependencyInjection\Reference;  
$container
   ->register('user', 'User')
   ->addMethodCall('setGreeter', array(new Reference('greeter')));

最后,我们注册了两个类, GreeterUser 之间有很强的关系。现在,我们可以安全地从容器中获取具有正确配置的Greeter类的User对象,如下面的代码所示。

$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 / configsymfony / yaml 组件以及 symfony /依赖注入 组件。

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部分定义了所有必需的参数。服务部分定义了所有对象。服务部分进一步分为多个部分,即 类,参数调用 。类指定实际的类。参数指定构造函数的参数。最后,调用指定了setter方法。另一个类可以使用@ symbol,@ greeter来引用。

parameters:
   greeter.text: 'Hello'
services:
   greeter:
      class: Greeter
      arguments: ['%greeter.text%']
   user:
      class: User
      calls:
         - [setGreeter, ['@greeter']]

现在, services.yml 可以加载和使用被配置 FileLoaderYamlFileLoader 如显示在下面的代码。

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 Web框架广泛使用依赖注入组件。所有组件都由集中式服务容器绑定。Symfony Web框架通过 容器 属性在其所有 Controller中 公开 容器 。我们可以通过它获取注册在其中的所有对象,例如记录器,邮件等。

$logger = $this->container->get('logger');
$logger->info('Hi');

要查找在容器中注册的对象,请使用以下命令。

cd /path/to/app
php bin/console debug:container

在安装章节中创建的 hello web应用程序中 有大约200多个对象。