SlideShare a Scribd company logo
1 of 103
Download to read offline
Dependency Injection
with PHP 5.3

Fabien Potencier
Fabien Potencier
Serial entrepreneur
Developer by passion
Founder of Sensio
Creator and lead developer of Symfony
On Twitter @fabpot
On github http://www.github.com/fabpot
Blog http://fabien.potencier.org/
Dependency Injection

A real world « web » example
In most web applications, you need to manage the user preferences

   –  The user language
   –  Whether the user is authenticated or not
   –  The user credentials
   –  …
This can be done with a User object

   –  setLanguage(), getLanguage()
   –  setAuthenticated(), isAuthenticated()
   –  addCredential(), hasCredential()
   –  ...
The User information
         need to be persisted
        between HTTP requests

We use the PHP session for the Storage
class SessionStorage
{
  function __construct($cookieName = 'PHP_SESS_ID')
  {
    session_name($cookieName);
    session_start();
  }

    function set($key, $value)
    {
      $_SESSION[$key] = $value;
    }

    // ...
}
class User
{
  protected $storage;

    function __construct()                      Very hard to
    {                                            customize
      $this->storage = new SessionStorage();
    }

    function setLanguage($language)
    {
      $this->storage->set('language', $language);
    }

    // ...
}                           Very easy
                              to use
$user = new User();
class User
{
  protected $storage;                  Very easy to
                                        customize
    function __construct($storage)
    {
      $this->storage = $storage;
    }
}

$storage = new SessionStorage();
$user = new User($storage);
                                     Slightly more
                                     difficult to use
That’s Dependency Injection

      Nothing more
Let’s understand why the first example
is not a good idea
I want to change the session cookie name
class User
{
  protected $storage;

    function __construct()
                                                    Hardcode it in the
    {                                                   User class
      $this->storage = new SessionStorage('SESSION_ID');
    }

    function setLanguage($language)
    {
      $this->storage->set('language', $language);
    }

    // ...
}

$user = new User();
class User
{
  protected $storage;

    function __construct()
    {
        $this->storage = new SessionStorage(STORAGE_SESSION_NAME);
    }
}
                                                              Add a global
                                                             configuration?
define('STORAGE_SESSION_NAME', 'SESSION_ID');

$user = new User();
class User
{
  protected $storage;

    function __construct($sessionName)
    {
      $this->storage = new SessionStorage($sessionName);
    }
}

$user = new User('SESSION_ID');
                                         Configure via
                                             User?
class User
{
  protected $storage;

  function __construct($storageOptions)
  {
    $this->storage = new SessionStorage($storageOptions
['session_name']);

$user = new User(
   array('session_name' => 'SESSION_ID')
);
                                      Configure with an
                                            array?
I want to change the session storage implementation

                   Filesystem
                     MySQL
                   Memcached
                       …
class User
{
  protected $storage;

    function __construct()                             Use a global
    {                                                 registry object?
      $this->storage = Registry::get('session_storage');
    }
}

$storage = new SessionStorage();
Registry::set('session_storage', $storage);
$user = new User();
Now, the User depends on the Registry
Instead of harcoding
    the Storage dependency
inside the User class constructor

Inject the Storage dependency
       in the User object
class User
{
  protected $storage;

    function __construct($storage)
    {
      $this->storage = $storage;
    }
}

$storage = new SessionStorage('SESSION_ID');
$user = new User($storage);
What are the advantages?
Use different Storage strategies
class User
{
  protected $storage;

    function __construct($storage)
    {
      $this->storage = $storage;
    }
}                                                   Use a different
                                                    Storage engine
$storage = new MySQLSessionStorage('SESSION_ID');
$user = new User($storage);
Configuration becomes natural
class User
{
  protected $storage;

    function __construct($storage)
    {
      $this->storage = $storage;
    }
}                                                   Configuration
                                                      is natural
$storage = new MySQLSessionStorage('SESSION_ID');
$user = new User($storage);
Wrap third-party classes (Interface / Adapter)
class User
{
  protected $storage;
                                                      Add an interface
    function __construct(SessionStorageInterface $storage)
    {
      $this->storage = $storage;
    }
}

interface SessionStorageInterface
{
  function get($key);

    function set($key, $value);
}
Mock the Storage object (for testing)
class User
{
  protected $storage;

    function __construct(SessionStorageInterface $storage)
    {
      $this->storage = $storage;
    }
}
                                                      Mock the Session
class SessionStorageForTests implements SessionStorageInterface
{
  protected $data = array();

    static function set($key, $value)
    {
      self::$data[$key] = $value;
    }
}
Use different Storage strategies
       Configuration becomes natural
Wrap third-party classes (Interface / Adapter)
    Mock the Storage object (for testing)


Easy without changing the User class
« Dependency Injection is where
   components are given their dependencies
    through their constructors, methods, or
             directly into fields. »
http://www.picocontainer.org/injection.html
$storage = new SessionStorage();

// constructor injection
$user = new User($storage);

// setter injection
$user = new User();
$user->setStorage($storage);

// property injection
$user = new User();
$user->storage = $storage;
A slightly more complex
web example
$request = new Request();
$response = new Response();

$storage = new FileSessionStorage('SESSION_ID');
$user = new User($storage);

$cache = new FileCache(
   array('dir' => dirname(__FILE__).'/cache')
);
$routing = new Routing($cache);
class Application
{
  function __construct()
  {
    $this->request = new WebRequest();
    $this->response = new WebResponse();

        $storage = new FileSessionStorage('SESSION_ID');
        $this->user = new User($storage);

        $cache = new FileCache(
           array('dir' => dirname(__FILE__).'/cache')
        );
        $this->routing = new Routing($cache);
    }
}

$application = new Application();
Back to square 1
class Application
{
  function __construct()
  {
    $this->request = new WebRequest();
    $this->response = new WebResponse();

        $storage = new FileSessionStorage('SESSION_ID');
        $this->user = new User($storage);

        $cache = new FileCache(
           array('dir' => dirname(__FILE__).'/cache')
        );
        $this->routing = new Routing($cache);
    }
}

$application = new Application();
We need a Container
     Describes objects
  and their dependencies

 Instantiates and configures
     objects on-demand
A container
SHOULD be able to manage
  ANY PHP object (POPO)


The objects MUST not know
  that they are managed
      by a container
•  Parameters
   –  The SessionStorageInterface implementation we want to use (the class name)
   –  The session name
•  Objects
   –  SessionStorage
   –  User
•  Dependencies
   –  User depends on a SessionStorageInterface implementation
Let’s build a simple container with PHP 5.3
DI Container

Managing parameters
class Container
{
  protected $parameters = array();

    public function setParameter($key, $value)
    {
      $this->parameters[$key] = $value;
    }

    public function getParameter($key)
    {
      return $this->parameters[$key];
    }
}
Decoupling


$container = new Container();                             Customization
$container->setParameter('session_name', 'SESSION_ID');
$container->setParameter('storage_class', 'SessionStorage');




$class = $container->getParameter('storage_class');
$sessionStorage = new $class($container->getParameter('session_name'));
$user = new User($sessionStorage);
                                                        Objects creation
class Container                            Using PHP
{                                         magic methods
  protected $parameters = array();

    public function __set($key, $value)
    {
      $this->parameters[$key] = $value;
    }

    public function __get($key)
    {
      return $this->parameters[$key];
    }
}
Interface
                                                          is cleaner


$container = new Container();
$container->session_name = 'SESSION_ID';
$container->storage_class = 'SessionStorage';

$sessionStorage = new $container->storage_class($container->session_name);
$user = new User($sessionStorage);
DI Container

Managing objects
We need a way to describe how to create objects,
    without actually instantiating anything!

      Anonymous functions to the rescue!
Anonymous Functions / Lambdas


               A lambda is a function
                   defined on the fly
                    with no name

function () { echo 'Hello world!'; };
Anonymous Functions / Lambdas

                A lambda can be stored
                      in a variable

$hello = function () { echo 'Hello world!'; };
Anonymous Functions / Lambdas

                And then it can be used
                as any other PHP callable

$hello();


call_user_func($hello);
Anonymous Functions / Lambdas

                    You can also pass a lambda
               as an argument to a function or method

function foo(Closure $func)
{
  $func();
}

foo($hello);
Fonctions anonymes
$hello = function ($name) { echo 'Hello '.$name; };

$hello('Fabien');

call_user_func($hello, 'Fabien');

function foo(Closure $func, $name)
{
  $func($name);
}

foo($hello, 'Fabien');
DI Container

Managing objects
class Container
{
  protected $parameters = array();
  protected $objects = array();

    public function __set($key, $value)
    {
      $this->parameters[$key] = $value;
    }

    public function __get($key)                           Store a lambda
    {
      return $this->parameters[$key];                    able to create the
                                                         object on-demand
    }

    public function setService($key, Closure $service)
    {
      $this->objects[$key] = $service;
    }

    public function getService($key)            Ask the closure to create
    {
      return $this->objects[$key]($this);        th e object and pass the
}
    }                                                current Container
$container = new Container();
$container->session_name = 'SESSION_ID';               Description
$container->storage_class = 'SessionStorage';
$container->setService('user', function ($c)
{
  return new User($c->getService('storage'));
});
$container->setService('storage', function ($c)
{
  return new $c->storage_class($c->session_name);
});


                                              Creating the User
                                          is now as easy as before
$user = $container->getService('user');
class Container
{
  protected $values = array();               Simplify the code
    function __set($id, $value)
    {
      $this->values[$id] = $value;
    }

    function __get($id)
    {
      if (is_callable($this->values[$id]))
      {
        return $this->values[$id]($this);
      }
      else
      {
        return $this->values[$id];
      }
    }
}
$container = new Container();
                                            Unified interface
$container->session_name = 'SESSION_ID';
$container->storage_class = 'SessionStorage';
$container->user = function ($c)
{
   return new User($c->storage);
};
$container->storage = function ($c)
{
   return new $c->storage_class($c->session_name);
};




$user = $container->user;
DI Container

Scope
For some objects, like the user,
   the container must always
    return the same instance
spl_object_hash($container->user)



            !==
spl_object_hash($container->user)
$container->user = function ($c)
{
  static $user;

  if (is_null($user))
  {
    $user = new User($c->storage);
  }

  return $user;
};
spl_object_hash($container->user)



            ===
spl_object_hash($container->user)
$container->user = $container->asShared(function ($c)
{
  return new User($c->storage);
});
A closure is a lambda
that remembers the context
      of its creation…
class Article
{
  public function __construct($title)
  {
    $this->title = $title;
  }

    public function getTitle()
    {
      return $this->title;
    }
}

$articles = array(
   new Article('Title 1'),
   new Article('Title 2'),
);
$mapper = function ($article)
{
   return $article->getTitle();
};

$titles = array_map($mapper, $articles);
$method = 'getTitle';

$mapper = function ($article) use($method)
{
   return $article->$method();
};

$method = 'getAuthor';

$titles = array_map($mapper, $articles);
$mapper = function ($method)
{
   return function ($article) use($method)
   {
      return $article->$method();
   };
};
$titles = array_map($mapper('getTitle'), $articles);


$authors = array_map($mapper('getAuthor'), $articles);
$container->user = $container->asShared(function ($c)
{
  return new User($c->storage);
});
function asShared(Closure $lambda)
{
  return function ($container) use ($lambda)
  {
    static $object;

      if (is_null($object))
      {
        $object = $lambda($container);
      }
      return $object;
    };
}
class Container
{
  protected $values = array();

    function __set($id, $value)
    {
      $this->values[$id] = $value;
    }

    function __get($id)
    {                                                            Error management
      if (!isset($this->values[$id]))
      {
        throw new InvalidArgumentException(sprintf('Value "%s" is not defined.', $id));
      }

        if (is_callable($this->values[$id]))
        {
          return $this->values[$id]($this);
        }
        else
        {
          return $this->values[$id];
        }
    }
}
class Container
{
  protected $values = array();

    function __set($id, $value)
    {
      $this->values[$id] = $value;
    }

    function __get($id)
    {
      if (!isset($this->values[$id]))
      {
        throw new InvalidArgumentException(sprintf('Value "%s" is not defined.', $id));
      }

        if (is_callable($this->values[$id]))
        {
          return $this->values[$id]($this);
        }
        else
        {
          return $this->values[$id];
        }
    }

    function asShared($callable)
    {


                                                                                          40 LOC for a fully-
      return function ($c) use ($callable)
      {
        static $object;

          if (is_null($object))
          {
            $object = $callable($c);
                                                                                          featured container
          }
          return $object;
        };
    }
}
I’m NOT advocating
the usage of lambdas everywhere


   This presentation is about
    showing how they work
     on practical examples
A DI Container
does NOT manage
 ALL your objects
Good rule of thumb:
    It manages “Global” objects

Objects with only one instance (!= Singletons)
LIKE
        a User, a Request,
a database Connection, a Logger, …
UNLIKE
Model objects (a Product, a blog Post, …)
Symfony Components
Dependency Injection
Rock-solid implementation of a DIC in PHP 5.3
At the core of the Symfony 2.0 framework

… which is one of the fastest framework
Very flexible

Configuration in PHP, XML, YAML, or INI
$container = new Builder();

$container->register('output', 'FancyOutput');
$container->
  register('message', 'Message')->
  setArguments(array(
     new sfServiceReference('output'),
     array('with_newline' => true)
  ))
;

$container->message->say('Hello World!');
services:
  output: { class: FancyOutput }
  message:
    class: Message
    arguments:
      - @output
      - { with_newline: true }
<container xmlns="http://symfony-project.org/schema/dic/services">
  <services>
    <service id="output" class="FancyOutput" />

    <service id="message" class="Message">
      <argument type="service" id="output" />
      <argument type="collection">
        <argument key="with_newline">true</argument>
      </argument>
    </service>
  </services>
</container>
<container xmlns="http://symfony-project.org/schema/dic/services">
  <import resource="parameters.yml" />
  <import resource="parameters.ini" />
  <import resource="services.xml" />
</container>


imports:
 - { resource: parameters.yml }
 - { resource: parameters.ini }
 - { resource: services.xml }
As fast as it can be
   The container can be
     “compiled” down
     to plain PHP code
use SymfonyComponentsDependencyInjectionContainer;
use SymfonyComponentsDependencyInjectionReference;
use SymfonyComponentsDependencyInjectionParameter;

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

    protected function getOutputService()
    {
      if (isset($this->shared['output'])) return $this->shared['output'];

        $instance = new FancyOutput();

        return $this->shared['output'] = $instance;
    }

    protected function getMessageService()
    {
      if (isset($this->shared['message'])) return $this->shared['message'];

        $instance = new Message($this->getOutputService(), array('with_newline' => true));

        return $this->shared['message'] = $instance;
    }
}
Semantic configuration
Thanks to an extension mechanism
<container xmlns="http://www.symfony-project.org/schema/dic/services">

  <zend:logger
     priority="debug"
     path="%kernel.root_dir%/logs/%kernel.environment%.log" />

  <doctrine:dbal dbname="dbname" username="root" password="" />

  <swift:mailer transport="gmail">
    <swift:username>fabien.potencier</swift:username>
    <swift:password>xxxxxx</swift:password>
  </swift:mailer>

</container>
<container xmlns="http://www.symfony-project.org/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:swift="http://www.symfony-project.org/schema/dic/swiftmailer"
    xmlns:doctrine="http://www.symfony-project.org/schema/dic/doctrine"
    xmlns:zend="http://www.symfony-project.org/schema/dic/zend"
    xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-
project.org/schema/dic/services/services-1.0.xsd
                        http://www.symfony-project.org/schema/dic/doctrine http://www.symfony-
project.org/schema/dic/doctrine/doctrine-1.0.xsd
                        http://www.symfony-project.org/schema/dic/swiftmailer http://
www.symfony-project.org/schema/dic/swiftmailer/swiftmailer-1.0.xsd">

  <zend:logger priority="debug" path="%kernel.root_dir%/logs/%kernel.environment%.log" />

                                                         auto-completion
  <doctrine:dbal dbname="dbname" username="root" password="" />

  <swift:mailer transport="gmail">                        and validation
    <swift:username>fabien.potencier</swift:username>
    <swift:password>xxxxxx</swift:password>                  with XSD
  </swift:mailer>

</container>
zend.logger:
  level: debug
  path:   %kernel.root_dir%/logs/%kernel.environment%.log

doctrine.dbal:
  dbname: dbname
  username: root
  password: ~

swift.mailer:
  transport: gmail
  username: fabien.potencier
  password: xxxxxxx
Everything is converted by the extension
     to plain services and parameters
            no overhead
Loader::registerExtension(new SwiftMailerExtension());
Loader::registerExtension(new DoctrineExtension());
Loader::registerExtension(new ZendExtension());

$loader = new XmlFileLoader(__DIR__);
$config = $loader->load('services.xml');

$container = new Builder();
$container->merge($config);

$container->mailer->...

$dumper = new PhpDumper($container);
echo $dumper->dump();
More about Dependency Injection
http://fabien.potencier.org/article/17/on-php-5-3-lambda-functions-and-closures


http://components.symfony-project.org/dependency-injection/ (5.2)


http://github.com/fabpot/symfony/tree/master/src/Symfony/Components/DependencyInjection/(5.3)



http://github.com/fabpot/pimple


http://twittee.org/
Remember, most of the time,
 you don’t need a Container
to use Dependency Injection
You can start to use and benefit from
    Dependency Injection today
by implementing it
        in your projects

  by using externals libraries
      that already use DI
without the need of a container
Symfony
Zend Framework
 ezComponents
    Doctrine
  Swift Mailer
      …
Questions?

My slides will be available on
slideshare.com/fabpot
Sensio S.A.
    92-98, boulevard Victor Hugo
        92 115 Clichy Cedex
              FRANCE
       Tél. : +33 1 40 99 80 80

               Contact
           Fabien Potencier
    fabien.potencier at sensio.com




  http://www.sensiolabs.com/
http://www.symfony-project.org/
 http://fabien.potencier.org/

More Related Content

What's hot

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Fabien Potencier
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Fabien Potencier
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 WorldFabien Potencier
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of LithiumNate Abele
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionNate Abele
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of LithiumNate Abele
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8PrinceGuru MS
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128PrinceGuru MS
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 

What's hot (20)

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 

Similar to Dependency Injection with PHP 5.3 Explained

Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)Fabien Potencier
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency InjectionRifat Nabi
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
Caching and Scaling WordPress using Fragment Caching
Caching and Scaling WordPress using Fragment CachingCaching and Scaling WordPress using Fragment Caching
Caching and Scaling WordPress using Fragment CachingErick Hitter
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
MUC - Moodle Universal Cache
MUC - Moodle Universal CacheMUC - Moodle Universal Cache
MUC - Moodle Universal CacheTim Hunt
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperJonathan Wage
 
Lecture 17 - PHP-Object-Orientation.pptx
Lecture 17 - PHP-Object-Orientation.pptxLecture 17 - PHP-Object-Orientation.pptx
Lecture 17 - PHP-Object-Orientation.pptxDavidLazar17
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionPhilip Norton
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 

Similar to Dependency Injection with PHP 5.3 Explained (20)

BEAR DI
BEAR DIBEAR DI
BEAR DI
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Caching and Scaling WordPress using Fragment Caching
Caching and Scaling WordPress using Fragment CachingCaching and Scaling WordPress using Fragment Caching
Caching and Scaling WordPress using Fragment Caching
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
PHP pod mikroskopom
PHP pod mikroskopomPHP pod mikroskopom
PHP pod mikroskopom
 
Oops in php
Oops in phpOops in php
Oops in php
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
MUC - Moodle Universal Cache
MUC - Moodle Universal CacheMUC - Moodle Universal Cache
MUC - Moodle Universal Cache
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document Mapper
 
Lecture 17 - PHP-Object-Orientation.pptx
Lecture 17 - PHP-Object-Orientation.pptxLecture 17 - PHP-Object-Orientation.pptx
Lecture 17 - PHP-Object-Orientation.pptx
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency Injection
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 

More from Fabien Potencier

Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Fabien Potencier
 
Caching on the Edge with Symfony2
Caching on the Edge with Symfony2Caching on the Edge with Symfony2
Caching on the Edge with Symfony2Fabien Potencier
 
Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Fabien Potencier
 
Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3Fabien Potencier
 
Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009Fabien Potencier
 
Symfony And Zend Framework Together 2009
Symfony And Zend Framework Together 2009Symfony And Zend Framework Together 2009
Symfony And Zend Framework Together 2009Fabien Potencier
 
Twig, the flexible, fast, and secure template language for PHP
Twig, the flexible, fast, and secure template language for PHPTwig, the flexible, fast, and secure template language for PHP
Twig, the flexible, fast, and secure template language for PHPFabien Potencier
 
symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)
symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)
symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)Fabien Potencier
 
The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)Fabien Potencier
 

More from Fabien Potencier (18)

Varnish
VarnishVarnish
Varnish
 
Look beyond PHP
Look beyond PHPLook beyond PHP
Look beyond PHP
 
Caching on the Edge
Caching on the EdgeCaching on the Edge
Caching on the Edge
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Caching on the Edge with Symfony2
Caching on the Edge with Symfony2Caching on the Edge with Symfony2
Caching on the Edge with Symfony2
 
Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Symfony Components
Symfony ComponentsSymfony Components
Symfony Components
 
PHP 5.3 in practice
PHP 5.3 in practicePHP 5.3 in practice
PHP 5.3 in practice
 
Symfony2 revealed
Symfony2 revealedSymfony2 revealed
Symfony2 revealed
 
Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3
 
Playing With PHP 5.3
Playing With PHP 5.3Playing With PHP 5.3
Playing With PHP 5.3
 
Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009
 
Symfony And Zend Framework Together 2009
Symfony And Zend Framework Together 2009Symfony And Zend Framework Together 2009
Symfony And Zend Framework Together 2009
 
Twig, the flexible, fast, and secure template language for PHP
Twig, the flexible, fast, and secure template language for PHPTwig, the flexible, fast, and secure template language for PHP
Twig, the flexible, fast, and secure template language for PHP
 
symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)
symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)
symfony: Un Framework Open-Source pour les Entreprises (Solutions Linux 2008)
 
The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)
 

Recently uploaded

Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 

Recently uploaded (20)

Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 

Dependency Injection with PHP 5.3 Explained

  • 1. Dependency Injection with PHP 5.3 Fabien Potencier
  • 2. Fabien Potencier Serial entrepreneur Developer by passion Founder of Sensio Creator and lead developer of Symfony On Twitter @fabpot On github http://www.github.com/fabpot Blog http://fabien.potencier.org/
  • 3. Dependency Injection A real world « web » example
  • 4. In most web applications, you need to manage the user preferences –  The user language –  Whether the user is authenticated or not –  The user credentials –  …
  • 5. This can be done with a User object –  setLanguage(), getLanguage() –  setAuthenticated(), isAuthenticated() –  addCredential(), hasCredential() –  ...
  • 6. The User information need to be persisted between HTTP requests We use the PHP session for the Storage
  • 7. class SessionStorage { function __construct($cookieName = 'PHP_SESS_ID') { session_name($cookieName); session_start(); } function set($key, $value) { $_SESSION[$key] = $value; } // ... }
  • 8. class User { protected $storage; function __construct() Very hard to { customize $this->storage = new SessionStorage(); } function setLanguage($language) { $this->storage->set('language', $language); } // ... } Very easy to use $user = new User();
  • 9. class User { protected $storage; Very easy to customize function __construct($storage) { $this->storage = $storage; } } $storage = new SessionStorage(); $user = new User($storage); Slightly more difficult to use
  • 11. Let’s understand why the first example is not a good idea
  • 12. I want to change the session cookie name
  • 13. class User { protected $storage; function __construct() Hardcode it in the { User class $this->storage = new SessionStorage('SESSION_ID'); } function setLanguage($language) { $this->storage->set('language', $language); } // ... } $user = new User();
  • 14. class User { protected $storage; function __construct() { $this->storage = new SessionStorage(STORAGE_SESSION_NAME); } } Add a global configuration? define('STORAGE_SESSION_NAME', 'SESSION_ID'); $user = new User();
  • 15. class User { protected $storage; function __construct($sessionName) { $this->storage = new SessionStorage($sessionName); } } $user = new User('SESSION_ID'); Configure via User?
  • 16. class User { protected $storage; function __construct($storageOptions) { $this->storage = new SessionStorage($storageOptions ['session_name']); $user = new User( array('session_name' => 'SESSION_ID') ); Configure with an array?
  • 17. I want to change the session storage implementation Filesystem MySQL Memcached …
  • 18. class User { protected $storage; function __construct() Use a global { registry object? $this->storage = Registry::get('session_storage'); } } $storage = new SessionStorage(); Registry::set('session_storage', $storage); $user = new User();
  • 19. Now, the User depends on the Registry
  • 20. Instead of harcoding the Storage dependency inside the User class constructor Inject the Storage dependency in the User object
  • 21. class User { protected $storage; function __construct($storage) { $this->storage = $storage; } } $storage = new SessionStorage('SESSION_ID'); $user = new User($storage);
  • 22. What are the advantages?
  • 24. class User { protected $storage; function __construct($storage) { $this->storage = $storage; } } Use a different Storage engine $storage = new MySQLSessionStorage('SESSION_ID'); $user = new User($storage);
  • 26. class User { protected $storage; function __construct($storage) { $this->storage = $storage; } } Configuration is natural $storage = new MySQLSessionStorage('SESSION_ID'); $user = new User($storage);
  • 27. Wrap third-party classes (Interface / Adapter)
  • 28. class User { protected $storage; Add an interface function __construct(SessionStorageInterface $storage) { $this->storage = $storage; } } interface SessionStorageInterface { function get($key); function set($key, $value); }
  • 29. Mock the Storage object (for testing)
  • 30. class User { protected $storage; function __construct(SessionStorageInterface $storage) { $this->storage = $storage; } } Mock the Session class SessionStorageForTests implements SessionStorageInterface { protected $data = array(); static function set($key, $value) { self::$data[$key] = $value; } }
  • 31. Use different Storage strategies Configuration becomes natural Wrap third-party classes (Interface / Adapter) Mock the Storage object (for testing) Easy without changing the User class
  • 32. « Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields. » http://www.picocontainer.org/injection.html
  • 33. $storage = new SessionStorage(); // constructor injection $user = new User($storage); // setter injection $user = new User(); $user->setStorage($storage); // property injection $user = new User(); $user->storage = $storage;
  • 34. A slightly more complex web example
  • 35. $request = new Request(); $response = new Response(); $storage = new FileSessionStorage('SESSION_ID'); $user = new User($storage); $cache = new FileCache( array('dir' => dirname(__FILE__).'/cache') ); $routing = new Routing($cache);
  • 36. class Application { function __construct() { $this->request = new WebRequest(); $this->response = new WebResponse(); $storage = new FileSessionStorage('SESSION_ID'); $this->user = new User($storage); $cache = new FileCache( array('dir' => dirname(__FILE__).'/cache') ); $this->routing = new Routing($cache); } } $application = new Application();
  • 38. class Application { function __construct() { $this->request = new WebRequest(); $this->response = new WebResponse(); $storage = new FileSessionStorage('SESSION_ID'); $this->user = new User($storage); $cache = new FileCache( array('dir' => dirname(__FILE__).'/cache') ); $this->routing = new Routing($cache); } } $application = new Application();
  • 39. We need a Container Describes objects and their dependencies Instantiates and configures objects on-demand
  • 40. A container SHOULD be able to manage ANY PHP object (POPO) The objects MUST not know that they are managed by a container
  • 41. •  Parameters –  The SessionStorageInterface implementation we want to use (the class name) –  The session name •  Objects –  SessionStorage –  User •  Dependencies –  User depends on a SessionStorageInterface implementation
  • 42. Let’s build a simple container with PHP 5.3
  • 44. class Container { protected $parameters = array(); public function setParameter($key, $value) { $this->parameters[$key] = $value; } public function getParameter($key) { return $this->parameters[$key]; } }
  • 45. Decoupling $container = new Container(); Customization $container->setParameter('session_name', 'SESSION_ID'); $container->setParameter('storage_class', 'SessionStorage'); $class = $container->getParameter('storage_class'); $sessionStorage = new $class($container->getParameter('session_name')); $user = new User($sessionStorage); Objects creation
  • 46. class Container Using PHP { magic methods protected $parameters = array(); public function __set($key, $value) { $this->parameters[$key] = $value; } public function __get($key) { return $this->parameters[$key]; } }
  • 47. Interface is cleaner $container = new Container(); $container->session_name = 'SESSION_ID'; $container->storage_class = 'SessionStorage'; $sessionStorage = new $container->storage_class($container->session_name); $user = new User($sessionStorage);
  • 49. We need a way to describe how to create objects, without actually instantiating anything! Anonymous functions to the rescue!
  • 50. Anonymous Functions / Lambdas A lambda is a function defined on the fly with no name function () { echo 'Hello world!'; };
  • 51. Anonymous Functions / Lambdas A lambda can be stored in a variable $hello = function () { echo 'Hello world!'; };
  • 52. Anonymous Functions / Lambdas And then it can be used as any other PHP callable $hello(); call_user_func($hello);
  • 53. Anonymous Functions / Lambdas You can also pass a lambda as an argument to a function or method function foo(Closure $func) { $func(); } foo($hello);
  • 54. Fonctions anonymes $hello = function ($name) { echo 'Hello '.$name; }; $hello('Fabien'); call_user_func($hello, 'Fabien'); function foo(Closure $func, $name) { $func($name); } foo($hello, 'Fabien');
  • 56. class Container { protected $parameters = array(); protected $objects = array(); public function __set($key, $value) { $this->parameters[$key] = $value; } public function __get($key) Store a lambda { return $this->parameters[$key]; able to create the object on-demand } public function setService($key, Closure $service) { $this->objects[$key] = $service; } public function getService($key) Ask the closure to create { return $this->objects[$key]($this); th e object and pass the } } current Container
  • 57. $container = new Container(); $container->session_name = 'SESSION_ID'; Description $container->storage_class = 'SessionStorage'; $container->setService('user', function ($c) { return new User($c->getService('storage')); }); $container->setService('storage', function ($c) { return new $c->storage_class($c->session_name); }); Creating the User is now as easy as before $user = $container->getService('user');
  • 58. class Container { protected $values = array(); Simplify the code function __set($id, $value) { $this->values[$id] = $value; } function __get($id) { if (is_callable($this->values[$id])) { return $this->values[$id]($this); } else { return $this->values[$id]; } } }
  • 59. $container = new Container(); Unified interface $container->session_name = 'SESSION_ID'; $container->storage_class = 'SessionStorage'; $container->user = function ($c) { return new User($c->storage); }; $container->storage = function ($c) { return new $c->storage_class($c->session_name); }; $user = $container->user;
  • 61. For some objects, like the user, the container must always return the same instance
  • 62. spl_object_hash($container->user) !== spl_object_hash($container->user)
  • 63. $container->user = function ($c) { static $user; if (is_null($user)) { $user = new User($c->storage); } return $user; };
  • 64. spl_object_hash($container->user) === spl_object_hash($container->user)
  • 65. $container->user = $container->asShared(function ($c) { return new User($c->storage); });
  • 66. A closure is a lambda that remembers the context of its creation…
  • 67. class Article { public function __construct($title) { $this->title = $title; } public function getTitle() { return $this->title; } } $articles = array( new Article('Title 1'), new Article('Title 2'), );
  • 68. $mapper = function ($article) { return $article->getTitle(); }; $titles = array_map($mapper, $articles);
  • 69. $method = 'getTitle'; $mapper = function ($article) use($method) { return $article->$method(); }; $method = 'getAuthor'; $titles = array_map($mapper, $articles);
  • 70. $mapper = function ($method) { return function ($article) use($method) { return $article->$method(); }; };
  • 71. $titles = array_map($mapper('getTitle'), $articles); $authors = array_map($mapper('getAuthor'), $articles);
  • 72. $container->user = $container->asShared(function ($c) { return new User($c->storage); });
  • 73. function asShared(Closure $lambda) { return function ($container) use ($lambda) { static $object; if (is_null($object)) { $object = $lambda($container); } return $object; }; }
  • 74. class Container { protected $values = array(); function __set($id, $value) { $this->values[$id] = $value; } function __get($id) { Error management if (!isset($this->values[$id])) { throw new InvalidArgumentException(sprintf('Value "%s" is not defined.', $id)); } if (is_callable($this->values[$id])) { return $this->values[$id]($this); } else { return $this->values[$id]; } } }
  • 75. class Container { protected $values = array(); function __set($id, $value) { $this->values[$id] = $value; } function __get($id) { if (!isset($this->values[$id])) { throw new InvalidArgumentException(sprintf('Value "%s" is not defined.', $id)); } if (is_callable($this->values[$id])) { return $this->values[$id]($this); } else { return $this->values[$id]; } } function asShared($callable) { 40 LOC for a fully- return function ($c) use ($callable) { static $object; if (is_null($object)) { $object = $callable($c); featured container } return $object; }; } }
  • 76. I’m NOT advocating the usage of lambdas everywhere This presentation is about showing how they work on practical examples
  • 77. A DI Container does NOT manage ALL your objects
  • 78. Good rule of thumb: It manages “Global” objects Objects with only one instance (!= Singletons)
  • 79. LIKE a User, a Request, a database Connection, a Logger, …
  • 80. UNLIKE Model objects (a Product, a blog Post, …)
  • 82. Rock-solid implementation of a DIC in PHP 5.3
  • 83. At the core of the Symfony 2.0 framework … which is one of the fastest framework
  • 84. Very flexible Configuration in PHP, XML, YAML, or INI
  • 85. $container = new Builder(); $container->register('output', 'FancyOutput'); $container-> register('message', 'Message')-> setArguments(array( new sfServiceReference('output'), array('with_newline' => true) )) ; $container->message->say('Hello World!');
  • 86. services: output: { class: FancyOutput } message: class: Message arguments: - @output - { with_newline: true }
  • 87. <container xmlns="http://symfony-project.org/schema/dic/services"> <services> <service id="output" class="FancyOutput" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument type="collection"> <argument key="with_newline">true</argument> </argument> </service> </services> </container>
  • 88. <container xmlns="http://symfony-project.org/schema/dic/services"> <import resource="parameters.yml" /> <import resource="parameters.ini" /> <import resource="services.xml" /> </container> imports: - { resource: parameters.yml } - { resource: parameters.ini } - { resource: services.xml }
  • 89. As fast as it can be The container can be “compiled” down to plain PHP code
  • 90. use SymfonyComponentsDependencyInjectionContainer; use SymfonyComponentsDependencyInjectionReference; use SymfonyComponentsDependencyInjectionParameter; class ProjectServiceContainer extends Container { protected $shared = array(); protected function getOutputService() { if (isset($this->shared['output'])) return $this->shared['output']; $instance = new FancyOutput(); return $this->shared['output'] = $instance; } protected function getMessageService() { if (isset($this->shared['message'])) return $this->shared['message']; $instance = new Message($this->getOutputService(), array('with_newline' => true)); return $this->shared['message'] = $instance; } }
  • 91. Semantic configuration Thanks to an extension mechanism
  • 92. <container xmlns="http://www.symfony-project.org/schema/dic/services"> <zend:logger priority="debug" path="%kernel.root_dir%/logs/%kernel.environment%.log" /> <doctrine:dbal dbname="dbname" username="root" password="" /> <swift:mailer transport="gmail"> <swift:username>fabien.potencier</swift:username> <swift:password>xxxxxx</swift:password> </swift:mailer> </container>
  • 93. <container xmlns="http://www.symfony-project.org/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:swift="http://www.symfony-project.org/schema/dic/swiftmailer" xmlns:doctrine="http://www.symfony-project.org/schema/dic/doctrine" xmlns:zend="http://www.symfony-project.org/schema/dic/zend" xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony- project.org/schema/dic/services/services-1.0.xsd http://www.symfony-project.org/schema/dic/doctrine http://www.symfony- project.org/schema/dic/doctrine/doctrine-1.0.xsd http://www.symfony-project.org/schema/dic/swiftmailer http:// www.symfony-project.org/schema/dic/swiftmailer/swiftmailer-1.0.xsd"> <zend:logger priority="debug" path="%kernel.root_dir%/logs/%kernel.environment%.log" /> auto-completion <doctrine:dbal dbname="dbname" username="root" password="" /> <swift:mailer transport="gmail"> and validation <swift:username>fabien.potencier</swift:username> <swift:password>xxxxxx</swift:password> with XSD </swift:mailer> </container>
  • 94. zend.logger: level: debug path: %kernel.root_dir%/logs/%kernel.environment%.log doctrine.dbal: dbname: dbname username: root password: ~ swift.mailer: transport: gmail username: fabien.potencier password: xxxxxxx
  • 95. Everything is converted by the extension to plain services and parameters no overhead
  • 96. Loader::registerExtension(new SwiftMailerExtension()); Loader::registerExtension(new DoctrineExtension()); Loader::registerExtension(new ZendExtension()); $loader = new XmlFileLoader(__DIR__); $config = $loader->load('services.xml'); $container = new Builder(); $container->merge($config); $container->mailer->... $dumper = new PhpDumper($container); echo $dumper->dump();
  • 97. More about Dependency Injection http://fabien.potencier.org/article/17/on-php-5-3-lambda-functions-and-closures http://components.symfony-project.org/dependency-injection/ (5.2) http://github.com/fabpot/symfony/tree/master/src/Symfony/Components/DependencyInjection/(5.3) http://github.com/fabpot/pimple http://twittee.org/
  • 98. Remember, most of the time, you don’t need a Container to use Dependency Injection
  • 99. You can start to use and benefit from Dependency Injection today
  • 100. by implementing it in your projects by using externals libraries that already use DI without the need of a container
  • 101. Symfony Zend Framework ezComponents Doctrine Swift Mailer …
  • 102. Questions? My slides will be available on slideshare.com/fabpot
  • 103. Sensio S.A. 92-98, boulevard Victor Hugo 92 115 Clichy Cedex FRANCE Tél. : +33 1 40 99 80 80 Contact Fabien Potencier fabien.potencier at sensio.com http://www.sensiolabs.com/ http://www.symfony-project.org/ http://fabien.potencier.org/