SlideShare une entreprise Scribd logo
1  sur  114
Télécharger pour lire hors ligne
Dependency Injection
with PHP 5.3... with a bit of PHP 5.4
Fabien Potencier
@fabpot
fabien@symfony.com
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;
                                                H ardcode it in the
    function __construct()                           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' => __DIR__.'/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
Using PHP
                                            magic methods
class Container
{
    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!
A lambda is a function
                  defined on the fly
                   with no name


function () { echo 'Hello world!'; };
A lambda can be stored
                      in a variable


$hello = function () { echo 'Hello world!'; };
And then it can be used
               as any other PHP callable

$hello();


call_user_func($hello);
You can also pass a lambda
           as an argument to a function or method

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

foo($hello);
$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; the closure to create
                                     Ask
    }                                          t and pass the
                                       the objec
    public function getService($key)      current Container
    {
        return $this->objects[$key]($this);
    }
}
Description
$container = new Container();
$container->session_name = 'SESSION_ID';
$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
$user = $container->getService('user');   is now as easy as before
Order does not
$container = new Container();                        matter
$container->setService('storage', function ($c) {
    return new $c->storage_class($c->session_name);
});

$container->setService('user', function ($c) {
    return new User($c->getService('storage'));
});

$container->session_name = 'SESSION_ID';

$container->storage_class = 'SessionStorage';
class Container                                  Simplify the code
{
    protected $values = array();

    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];
        }
    }
}
Unified interface

$container = new Container();
$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)
    {
        return function ($c) use ($callable) {
            static $object;

             if (is_null($object)) {                                   40 LO C for a fully-
             }
                 $object = $callable($c);
                                                                       feature d container
             return $object;
        };
    }
}
$container = new Container();
$container->session_name = 'SESSION_ID';
$container->storage_class = 'SessionStorage';
$container->user = $container->asShared(function ($c) {
    return new User($c->storage);
});
$container->storage = $container->asShared(function ($c) {
    return new $c->storage_class($c->session_name);
});
github.com/fabpot/pimple
... and with PHP 5.4?
$container = new Container();
$container->session_name = 'SESSION_ID';
$container->storage_class = 'SessionStorage';
$container->user = $container->asShared(function () {
    return new User($this->storage);
});
$container->storage = $container->asShared(function () {
    return new $this->storage_class($this->session_name);
});
$title = function () {
    echo $this->title;
};

print get_class($title);
// Closure
class Article
{
    public $title;

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

$a = new Article('Title 1');

$title = function () {
    echo $this->title;
};

$getTitle = $title->bindTo($a);
$getTitle();
class Article
{
    private $title;

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

$a = new Article('Title 1');

$title = function () {
    echo $this->title;
};

$getTitle = $title->bindTo($a, $a);
$getTitle();
wiki.php.net/rfc/closures/object-extension
if (is_callable($this->values[$id])) {
    $value = $value->bindTo($this);

    return $this->values[$id]();
} else {
  return $this->values[$id];
}
function asShared($callable)
{
    $callable = $callable->bindTo($this);

    return function () use ($callable) {
        static $object;

         if (is_null($object)) {
             $object = $callable();
         }

         return $object;
    };
}
$container = new Container();
$container->session_name = 'SESSION_ID';
$container->storage_class = 'SessionStorage';
$container->user = $container->asShared(function () {
    return new User($this->storage);
});
$container->storage = $container->asShared(function () {
    return new $this->storage_class($this->session_name);
});
A DI Container
does NOT manage
 ALL your objects
A DI Container / Service Container
     manages your SERVICES
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, …)
Performance
The Symfony2 Dependency Injection
Component
Rock-solid implementation of a DIC in PHP 5.3
At the core of the Symfony2 framework
namespace SymfonyComponentDependencyInjection;

interface ContainerInterface
{
      function set($id, $service, $scope = self::SCOPE_CONTAINER);
      function get($id, $invalidBehavior =
self::EXCEPTION_ON_INVALID_REFERENCE);
      function has($id);
      function getParameter($name);
      function hasParameter($name);
      function setParameter($name, $value);

    function   enterScope($name);
    function   leaveScope($name);
    function   addScope(ScopeInterface $scope);
    function   hasScope($name);
    function   isScopeActive($name);
}
Very flexible
Configuration in PHP, XML, YAML, or INI
use SymfonyComponentDependencyInjectionContainerBuilder;
use SymfonyComponentDependencyInjectionReference;

$sc = new ContainerBuilder();
$sc->setParameter('session_name', 'SESSION_ID');
$sc->setParameter('storage_class', 'SessionStorage');
$sc
    ->register('user', 'User')
    ->addArgument(new Reference('storage'))
;
$sc->register('storage', '%storage_class%')
    ->addArgument('%session_name%')
;

$sc->get('user');
parameters:
    session_name: SESSION_ID
    storage_class: SessionStorage

services:
  user:
    class: User
    arguments: [@storage]
  storage:
    class: %storage_class%
    arguments: [%session_name%]
use SymfonyComponentDependencyInjectionLoaderYamlFileLoader;
use SymfonyComponentConfigFileLocator;

$sc = new ContainerBuilder();

$loader = new YamlFileLoader($sc, new FileLocator(__DIR__));
$loader->load('services.yml');
<container xmlns="http://symfony.com/schema/dic/services">
    <parameters>
        <parameter key="session_name">SESSION_ID</parameter>
        <parameter key="storage_class">SessionStorage</parameter>
    </parameters>

    <services>
        <service id="user" class="User">
            <argument type="service" id="storage" />
        </service>

        <service id="storage" class="%storage_class%">
             <argument>%session_name%</argument>
        </service>
    </services>
</container>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
    <parameters>
        <parameter key="session_name">SESSION_ID</parameter>
        <parameter key="storage_class">SessionStorage</parameter>
    </parameters>
    <services>
        <service id="user" class="User">
            <argument type="service" id="storage" />
        </service>

        <service id="storage" class="%storage_class%">
             <argument>%session_name%</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 SymfonyComponentDependencyInjectionDumperPhpDumper;

$dumper = new PhpDumper($sc);
echo $dumper->dump();
class ProjectServiceContainer extends Container
{
    public function __construct()
    {
        parent::__construct(new ParameterBag($this->getDefaultParameters()));
    }

    protected function getStorageService()
    {
        $class = $this->getParameter('storage_class');
        return $this->services['storage'] = new $class($this-
>getParameter('session_name'));
    }

    protected function getUserService()
    {
        return $this->services['user'] = new User($this->get('storage'));
    }

    protected function getDefaultParameters()
    {
        return array(
            'session_name' => 'SESSION_ID',
            'storage_class' => 'SessionStorage',
        );
    }
}
$dumper = new GraphvizDumper($sc);
echo $dumper->dump();

$ doc -Tpng -o sc.png sc.dot
There is more...


 Semantic configuration
   Scope management
Compiler passes (optimizers)
          Aliases
   Abstract definitions
             ...
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
   Doctrine
  Swift Mailer
      …
Questions?
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://sensiolabs.com/
     http://symfony.com/
http://fabien.potencier.org/

Contenu connexe

Tendances

Introduction of computer basic skills on windows 7
Introduction of computer basic skills on windows 7Introduction of computer basic skills on windows 7
Introduction of computer basic skills on windows 7kalindunimanthadonz
 
Intrusion detection and prevention system for network using Honey pots and Ho...
Intrusion detection and prevention system for network using Honey pots and Ho...Intrusion detection and prevention system for network using Honey pots and Ho...
Intrusion detection and prevention system for network using Honey pots and Ho...Eng. Mohammed Ahmed Siddiqui
 
software History
software Historysoftware History
software HistoryAvinash Avi
 
Mtms lec-2 [1]
Mtms lec-2 [1]Mtms lec-2 [1]
Mtms lec-2 [1]nyamka0928
 
санах ой
санах ойсанах ой
санах ойshulam
 
Computer graphic 1
Computer graphic 1Computer graphic 1
Computer graphic 1adminse03
 
программ хангамжийн їндсэн ойлголт
программ хангамжийн їндсэн ойлголтпрограмм хангамжийн їндсэн ойлголт
программ хангамжийн їндсэн ойлголтshulam
 
Тооллын систем (Number system)
Тооллын систем (Number system)Тооллын систем (Number system)
Тооллын систем (Number system)Altansukh Mainbayar
 
Community reporting system: road violation
Community reporting system: road violationCommunity reporting system: road violation
Community reporting system: road violationjournalBEEI
 
Internet anonymity and privacy
Internet anonymity and privacyInternet anonymity and privacy
Internet anonymity and privacyDooremoore
 
Social Engineering Audit & Security Awareness
Social Engineering Audit & Security AwarenessSocial Engineering Audit & Security Awareness
Social Engineering Audit & Security AwarenessCBIZ, Inc.
 
компьютер флашнаас форматлах.
компьютер флашнаас форматлах.компьютер флашнаас форматлах.
компьютер флашнаас форматлах.Batzaya Bayar-erdene
 
Computer Security Chapter 1
Computer Security Chapter 1Computer Security Chapter 1
Computer Security Chapter 1Temesgen Berhanu
 

Tendances (20)

Introduction of computer basic skills on windows 7
Introduction of computer basic skills on windows 7Introduction of computer basic skills on windows 7
Introduction of computer basic skills on windows 7
 
Intrusion detection and prevention system for network using Honey pots and Ho...
Intrusion detection and prevention system for network using Honey pots and Ho...Intrusion detection and prevention system for network using Honey pots and Ho...
Intrusion detection and prevention system for network using Honey pots and Ho...
 
software History
software Historysoftware History
software History
 
Android гэж юу вэ
Android гэж юу вэAndroid гэж юу вэ
Android гэж юу вэ
 
Mtms lec-2 [1]
Mtms lec-2 [1]Mtms lec-2 [1]
Mtms lec-2 [1]
 
санах ой
санах ойсанах ой
санах ой
 
Computer graphic 1
Computer graphic 1Computer graphic 1
Computer graphic 1
 
Security and Linux Security
Security and Linux SecuritySecurity and Linux Security
Security and Linux Security
 
программ хангамжийн їндсэн ойлголт
программ хангамжийн їндсэн ойлголтпрограмм хангамжийн їндсэн ойлголт
программ хангамжийн їндсэн ойлголт
 
Ch02 System Threats and Risks
Ch02 System Threats and RisksCh02 System Threats and Risks
Ch02 System Threats and Risks
 
Тооллын систем (Number system)
Тооллын систем (Number system)Тооллын систем (Number system)
Тооллын систем (Number system)
 
Community reporting system: road violation
Community reporting system: road violationCommunity reporting system: road violation
Community reporting system: road violation
 
Lecture 1 2
Lecture 1 2Lecture 1 2
Lecture 1 2
 
Internet anonymity and privacy
Internet anonymity and privacyInternet anonymity and privacy
Internet anonymity and privacy
 
Social Engineering Audit & Security Awareness
Social Engineering Audit & Security AwarenessSocial Engineering Audit & Security Awareness
Social Engineering Audit & Security Awareness
 
компьютер флашнаас форматлах.
компьютер флашнаас форматлах.компьютер флашнаас форматлах.
компьютер флашнаас форматлах.
 
Virus
VirusVirus
Virus
 
хичээл
хичээлхичээл
хичээл
 
Personal security
Personal securityPersonal security
Personal security
 
Computer Security Chapter 1
Computer Security Chapter 1Computer Security Chapter 1
Computer Security Chapter 1
 

En vedette

[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -
[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -
[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -Shuji Kikuchi
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)Yoshitaka Kawashima
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるpospome
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)Yoshitaka Kawashima
 
片手間MySQLチューニング戦略
片手間MySQLチューニング戦略片手間MySQLチューニング戦略
片手間MySQLチューニング戦略yoku0825
 
If文から機械学習への道
If文から機械学習への道If文から機械学習への道
If文から機械学習への道nishio
 
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3 データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3 Hiroshi Ito
 

En vedette (7)

[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -
[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -
[AKIBA.AWS] EC2の基礎 - パフォーマンスを100%引き出すオプション設定 -
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 
片手間MySQLチューニング戦略
片手間MySQLチューニング戦略片手間MySQLチューニング戦略
片手間MySQLチューニング戦略
 
If文から機械学習への道
If文から機械学習への道If文から機械学習への道
If文から機械学習への道
 
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3 データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
 

Similaire à Dependency injection in PHP 5.3/5.4

Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Fabien Potencier
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010Fabien Potencier
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien 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
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Fabien Potencier
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Fabien Potencier
 
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
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of LithiumNate Abele
 
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
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
MUC - Moodle Universal Cache
MUC - Moodle Universal CacheMUC - Moodle Universal Cache
MUC - Moodle Universal CacheTim Hunt
 

Similaire à Dependency injection in PHP 5.3/5.4 (20)

Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
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
 
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
 
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
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
 
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
 
Oops in php
Oops in phpOops in php
Oops in php
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
PHP pod mikroskopom
PHP pod mikroskopomPHP pod mikroskopom
PHP pod mikroskopom
 
MUC - Moodle Universal Cache
MUC - Moodle Universal CacheMUC - Moodle Universal Cache
MUC - Moodle Universal Cache
 

Plus de Fabien Potencier

Plus de Fabien Potencier (20)

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
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Caching on the Edge with Symfony2
Caching on the Edge with Symfony2Caching on the Edge with Symfony2
Caching on the Edge with Symfony2
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
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
 
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
 
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
 

Dernier

What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 

Dernier (20)

What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 

Dependency injection in PHP 5.3/5.4

  • 1. Dependency Injection with PHP 5.3... with a bit of PHP 5.4 Fabien Potencier @fabpot fabien@symfony.com
  • 2. Dependency Injection A real world « web » example
  • 3. In most web applications, you need to manage the user preferences –The user language –Whether the user is authenticated or not –The user credentials –…
  • 4. This can be done with a User object –setLanguage(), getLanguage() –setAuthenticated(), isAuthenticated() –addCredential(), hasCredential() –...
  • 5. The User information need to be persisted between HTTP requests We use the PHP session for the Storage
  • 6. class SessionStorage { function __construct($cookieName = 'PHP_SESS_ID') { session_name($cookieName); session_start(); } function set($key, $value) { $_SESSION[$key] = $value; } // ... }
  • 7. 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();
  • 8. 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
  • 10. Let’s understand why the first example is not a good idea
  • 11. I want to change the session cookie name
  • 12. class User { protected $storage; H ardcode it in the function __construct() User class { $this->storage = new SessionStorage('SESSION_ID'); } function setLanguage($language) { $this->storage->set('language', $language); } // ... } $user = new User();
  • 13. 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();
  • 14. class User { protected $storage; function __construct($sessionName) { $this->storage = new SessionStorage($sessionName); } } $user = new User('SESSION_ID'); Configure via User?
  • 15. 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?
  • 16. I want to change the session storage implementation Filesystem MySQL Memcached …
  • 17. 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();
  • 18. Now, the User depends on the Registry
  • 19. Instead of harcoding the Storage dependency inside the User class constructor Inject the Storage dependency in the User object
  • 20. class User { protected $storage; function __construct($storage) { $this->storage = $storage; } } $storage = new SessionStorage('SESSION_ID'); $user = new User($storage);
  • 21. What are the advantages?
  • 22. Use different Storage strategies
  • 23. class User { protected $storage; function __construct($storage) { $this->storage = $storage; } Use a different } Storage engine $storage = new MySQLSessionStorage('SESSION_ID'); $user = new User($storage);
  • 25. class User { protected $storage; function __construct($storage) { $this->storage = $storage; } Configuration } is natural $storage = new MySQLSessionStorage('SESSION_ID'); $user = new User($storage);
  • 26. Wrap third-party classes (Interface / Adapter)
  • 27. class User { protected $storage; Add an interface function __construct(SessionStorageInterface $storage) { $this->storage = $storage; } } interface SessionStorageInterface { function get($key); function set($key, $value); }
  • 28. Mock the Storage object (for testing)
  • 29. 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; } }
  • 30. 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
  • 31. « Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields. » http://www.picocontainer.org/injection.html
  • 32. $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;
  • 33. A slightly more complex web example
  • 34. $request = new Request(); $response = new Response(); $storage = new FileSessionStorage('SESSION_ID'); $user = new User($storage); $cache = new FileCache( array('dir' => __DIR__.'/cache') ); $routing = new Routing($cache);
  • 35. 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();
  • 37. 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. We need a Container Describes objects and their dependencies Instantiates and configures objects on-demand
  • 39. A container SHOULD be able to manage ANY PHP object (POPO) The objects MUST not know that they are managed by a container
  • 40. • Parameters –The SessionStorageInterface implementation we want to use (the class name) –The session name • Objects –SessionStorage –User • Dependencies –User depends on a SessionStorageInterface implementation
  • 41. Let’s build a simple container with PHP 5.3
  • 43. class Container { protected $parameters = array(); public function setParameter($key, $value) { $this->parameters[$key] = $value; } public function getParameter($key) { return $this->parameters[$key]; } }
  • 44. 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
  • 45. Using PHP magic methods class Container { protected $parameters = array(); public function __set($key, $value) { $this->parameters[$key] = $value; } public function __get($key) { return $this->parameters[$key]; } }
  • 46. 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);
  • 48. We need a way to describe how to create objects, without actually instantiating anything! Anonymous functions to the rescue!
  • 49. A lambda is a function defined on the fly with no name function () { echo 'Hello world!'; };
  • 50. A lambda can be stored in a variable $hello = function () { echo 'Hello world!'; };
  • 51. And then it can be used as any other PHP callable $hello(); call_user_func($hello);
  • 52. You can also pass a lambda as an argument to a function or method function foo(Closure $func) { $func(); } foo($hello);
  • 53. $hello = function ($name) { echo 'Hello '.$name; }; $hello('Fabien'); call_user_func($hello, 'Fabien'); function foo(Closure $func, $name) { $func($name); } foo($hello, 'Fabien');
  • 55. 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; the closure to create Ask } t and pass the the objec public function getService($key) current Container { return $this->objects[$key]($this); } }
  • 56. Description $container = new Container(); $container->session_name = 'SESSION_ID'; $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 $user = $container->getService('user'); is now as easy as before
  • 57. Order does not $container = new Container(); matter $container->setService('storage', function ($c) { return new $c->storage_class($c->session_name); }); $container->setService('user', function ($c) { return new User($c->getService('storage')); }); $container->session_name = 'SESSION_ID'; $container->storage_class = 'SessionStorage';
  • 58. class Container Simplify the code { protected $values = array(); 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. Unified interface $container = new Container(); $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) { return function ($c) use ($callable) { static $object; if (is_null($object)) { 40 LO C for a fully- } $object = $callable($c); feature d container return $object; }; } }
  • 76. $container = new Container(); $container->session_name = 'SESSION_ID'; $container->storage_class = 'SessionStorage'; $container->user = $container->asShared(function ($c) { return new User($c->storage); }); $container->storage = $container->asShared(function ($c) { return new $c->storage_class($c->session_name); });
  • 78. ... and with PHP 5.4?
  • 79. $container = new Container(); $container->session_name = 'SESSION_ID'; $container->storage_class = 'SessionStorage'; $container->user = $container->asShared(function () { return new User($this->storage); }); $container->storage = $container->asShared(function () { return new $this->storage_class($this->session_name); });
  • 80. $title = function () { echo $this->title; }; print get_class($title); // Closure
  • 81. class Article { public $title; public function __construct($title) { $this->title = $title; } } $a = new Article('Title 1'); $title = function () { echo $this->title; }; $getTitle = $title->bindTo($a); $getTitle();
  • 82. class Article { private $title; public function __construct($title) { $this->title = $title; } } $a = new Article('Title 1'); $title = function () { echo $this->title; }; $getTitle = $title->bindTo($a, $a); $getTitle();
  • 84. if (is_callable($this->values[$id])) { $value = $value->bindTo($this); return $this->values[$id](); } else { return $this->values[$id]; }
  • 85. function asShared($callable) { $callable = $callable->bindTo($this); return function () use ($callable) { static $object; if (is_null($object)) { $object = $callable(); } return $object; }; }
  • 86. $container = new Container(); $container->session_name = 'SESSION_ID'; $container->storage_class = 'SessionStorage'; $container->user = $container->asShared(function () { return new User($this->storage); }); $container->storage = $container->asShared(function () { return new $this->storage_class($this->session_name); });
  • 87. A DI Container does NOT manage ALL your objects
  • 88. A DI Container / Service Container manages your SERVICES
  • 89. Good rule of thumb: It manages “Global” objects Objects with only one instance (!= Singletons)
  • 90. LIKE a User, a Request, a database Connection, a Logger, …
  • 91. UNLIKE Model objects (a Product, a blog Post, …)
  • 93. The Symfony2 Dependency Injection Component
  • 94. Rock-solid implementation of a DIC in PHP 5.3
  • 95. At the core of the Symfony2 framework
  • 96. namespace SymfonyComponentDependencyInjection; interface ContainerInterface { function set($id, $service, $scope = self::SCOPE_CONTAINER); function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE); function has($id); function getParameter($name); function hasParameter($name); function setParameter($name, $value); function enterScope($name); function leaveScope($name); function addScope(ScopeInterface $scope); function hasScope($name); function isScopeActive($name); }
  • 97. Very flexible Configuration in PHP, XML, YAML, or INI
  • 98. use SymfonyComponentDependencyInjectionContainerBuilder; use SymfonyComponentDependencyInjectionReference; $sc = new ContainerBuilder(); $sc->setParameter('session_name', 'SESSION_ID'); $sc->setParameter('storage_class', 'SessionStorage'); $sc ->register('user', 'User') ->addArgument(new Reference('storage')) ; $sc->register('storage', '%storage_class%') ->addArgument('%session_name%') ; $sc->get('user');
  • 99. parameters: session_name: SESSION_ID storage_class: SessionStorage services: user: class: User arguments: [@storage] storage: class: %storage_class% arguments: [%session_name%]
  • 100. use SymfonyComponentDependencyInjectionLoaderYamlFileLoader; use SymfonyComponentConfigFileLocator; $sc = new ContainerBuilder(); $loader = new YamlFileLoader($sc, new FileLocator(__DIR__)); $loader->load('services.yml');
  • 101. <container xmlns="http://symfony.com/schema/dic/services"> <parameters> <parameter key="session_name">SESSION_ID</parameter> <parameter key="storage_class">SessionStorage</parameter> </parameters> <services> <service id="user" class="User"> <argument type="service" id="storage" /> </service> <service id="storage" class="%storage_class%"> <argument>%session_name%</argument> </service> </services> </container>
  • 102. <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <parameters> <parameter key="session_name">SESSION_ID</parameter> <parameter key="storage_class">SessionStorage</parameter> </parameters> <services> <service id="user" class="User"> <argument type="service" id="storage" /> </service> <service id="storage" class="%storage_class%"> <argument>%session_name%</argument> </service> </services> </container>
  • 103. <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 }
  • 104. As fast as it can be The container can be “compiled” down to plain PHP code
  • 105. use SymfonyComponentDependencyInjectionDumperPhpDumper; $dumper = new PhpDumper($sc); echo $dumper->dump();
  • 106. class ProjectServiceContainer extends Container { public function __construct() { parent::__construct(new ParameterBag($this->getDefaultParameters())); } protected function getStorageService() { $class = $this->getParameter('storage_class'); return $this->services['storage'] = new $class($this- >getParameter('session_name')); } protected function getUserService() { return $this->services['user'] = new User($this->get('storage')); } protected function getDefaultParameters() { return array( 'session_name' => 'SESSION_ID', 'storage_class' => 'SessionStorage', ); } }
  • 107. $dumper = new GraphvizDumper($sc); echo $dumper->dump(); $ doc -Tpng -o sc.png sc.dot
  • 108. There is more... Semantic configuration Scope management Compiler passes (optimizers) Aliases Abstract definitions ...
  • 109. Remember, most of the time, you don’t need a Container to use Dependency Injection
  • 110. You can start to use and benefit from Dependency Injection today
  • 111. by implementing it in your projects by using externals libraries that already use DI without the need of a container
  • 112. Symfony Zend Framework Doctrine Swift Mailer …
  • 114. 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://sensiolabs.com/ http://symfony.com/ http://fabien.potencier.org/