a SENSIOLABS Product
Symfony

Dependency Injection
Reinventing how you manage
PHP classes

The Symfony Service Container

RELEASE INFORMATION

You are currently browsing the documentation for the trunk version.

Until now, we have talked about general concepts. The first two introductory chapters were important to better understand the implementation we will talk about in this chapter and in the following ones. It is now time to dive into the Symfony Service Container component implementation.

The Symfony Dependency Injection Container is managed by a class named sfServiceContainer. It is a very lightweight class that implements the basic features we talked about in the previous article.

In Symfony speak, a service is any object managed by the container. In the Zend_Mail example from the last chapter, we had two of them: the mailer service and the mail_transport service:

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;
  }
}

If we make the Container class extend the sfServiceContainer Symfony class, we can simplify the code a bit:

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;
  }
}

That's not much, but it will give us a more powerful and clean interface. Here are the main changes we made:

A service identifier must be unique and must be made of letters, numbers, underscores, and dots. Dots are useful to define "namespaces" within your container (for instance mail.mailer and mail.transport).

Let's see how to use the new container class:

require_once '/PATH/TO/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();
 
$sc = new Container(array(
  'mailer.username' => 'foo',
  'mailer.password' => 'bar',
  'mailer.class'    => 'Zend_Mail',
));
 
$mailer = $sc->mailer;

Now, because the Container class extends the sfServiceContainer class, we can enjoy a cleaner interface:

Using the sfServiceContainer class is very useful when you have a very small number of services to manage; even if you still need to do a lot of groundwork yourself, and duplicate a lot of code. But, if the number of services to be managed starts to grow beyond a few of them, we need a better way to describe the services.

That's why, most of the time, you don't use the sfServiceContainer class directly. It was nonetheless important to take some time to describe it as it is the cornerstone of the Symfony dependency injection container implementation.

powered by symfony - "symfony" is a trademark of Fabien Potencier, all rights reserved - The components "animals" are © 2009 Sensio Labs

The Sensio Labs Network

Since 1998, Sensio Labs has been promoting the Open-Source software movement by providing quality web application development, training, consulting.
Sensio Labs also supports several large Open-Source projects.