三. Symfony服务容器介绍

2017-07-25  本文已影响0人  Anomaly

此文是本人翻译的来自国外某网站一篇文章 Do you need a Dependency Injection Container?

这篇文章是一系列关于依赖注入和PHP轻量级容器实现文章中的一部分:
Part 1: What is Dependency Injection?
Part 2: Do you need a Dependency Injection Container?
Part 3: Introduction to the Symfony Service Container
Part 4: Symfony Service Container: Using a Builder to create Services
Part 5: Symfony Service Container: Using XML or YAML to describe Services
Part 6: The Need for Speed

在依赖注入这系列文章里,之前我们已经谈过一些基本思想。前面2篇文章介绍的东西对于更好的理解我们接下来文章要说的非常重要,现在是时候了解Symfony2里面服务容器的实现了。
Symfony里面依赖注入容器是被一个叫sfServiceContainer的类管理的,这是一个非常轻的类,它实现了我们上篇文章里面说到的基本特性。
在Symfony里面,一个服务就是一个被容器管理的对象。在上一篇文章Zend_Mail例子里,我们有2个:mailer服务和mail_transport服务:

class Container
{
  static protected $shared = array();

  protected $parameters = array();

  public function __construct(array $parameters = array())
  {
    $this->parameters = $parameters;
  }

  public function getMailTransport()
  {
    return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
      'auth'     => 'login',
      'username' => $this->parameters['mailer.username'],
      'password' => $this->parameters['mailer.password'],
      'ssl'      => 'ssl',
      'port'     => 465,
    ));
  }

  public function getMailer()
  {
    if (isset(self::$shared['mailer']))
    {
      return self::$shared['mailer'];
    }

    $class = $this->parameters['mailer.class'];

    $mailer = new $class();
    $mailer->setDefaultTransport($this->getMailTransport());

    return self::$shared['mailer'] = $mailer;
  }
}

如果我们让Container类继承sfServiceContainer类,就可以简化一下代码:

class Container extends sfServiceContainer
{
  static protected $shared = array();

  protected function getMailTransportService()
  {
    return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
      'auth'     => 'login',
      'username' => $this['mailer.username'],
      'password' => $this['mailer.password'],
      'ssl'      => 'ssl',
      'port'     => 465,
    ));
  }

  protected function getMailerService()
  {
    if (isset(self::$shared['mailer']))
    {
      return self::$shared['mailer'];
    }

    $class = $this['mailer.class'];

    $mailer = new $class();
    $mailer->setDefaultTransport($this->getMailTransportService());

    return self::$shared['mailer'] = $mailer;
  }
}

这还不够,但是这会给我们一个稍微强大和干净的接口。我们做了以下改变:

让我们看看如何使用新的容器类:

require_once 'PATH/TO/sf/lib/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();

$sc = new Container(array(
  'mailer.username' => 'foo',
  'mailer.password' => 'bar',
  'mailer.class'    => 'Zend_Mail',
));

$mailer = $sc->mailer;

现在,因为Container类已经继承了sfServiceContainer类,接口就清晰多了:

    if ($sc->hasService('mailer'))
    {
      $mailer = $sc->getService('mailer');
    }

    $sc->setService('mailer', $mailer);
   if (isset($sc->mailer))
    {
      $mailer = $sc->mailer;
    }

    $sc->mailer = $mailer;
 if (!$sc->hasParameter('mailer_class'))
    {
      $sc->setParameter('mailer_class', 'Zend_Mail');
    }

    echo $sc->getParameter('mailer_class');

    // Override all parameters of the container
    $sc->setParameters($parameters);

    // Adds parameters
    $sc->addParameters($parameters);
 if (!isset($sc['mailer.class']))
    {
      $sc['mailer.class'] = 'Zend_Mail';
    }

    $mailerClass = $sc['mailer.class'];
  foreach ($sc as $id => $service)
    {
      echo sprintf("Service %s is an instance of %s.\n", $id, get_class($service));
    }

当你有少量服务需要管理的话使用sfServiceContainer类非常有用方便,即使这样你还得做很多基础工作。如果你需要管理的服务增长到一定数量级,我们就需要一种更好的方式。

这也就是为什么大多数时候你并不需要直接使用sfServiceContainer类,但是它作为Symfony依赖注入容器实现的基石,我们还是需要花一些时间去描述它。

在下一篇文章里面,我们会看一下sfServiceContainerBuilder类,它简化了服务定义的过程。

上一篇下一篇

猜你喜欢

热点阅读