Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to DI(C)

Introduction to DI(C)

Quick introduction to Dependency Injection (Container).

Radek Benkel

May 21, 2012
Tweet

More Decks by Radek Benkel

Other Decks in Technology

Transcript

  1. Introduction to DI(C)
    meet.php # . .
    http://meetphp.pl/

    View Slide

  2. $speaker = new Speaker;
    $speaker->name = "Radosław Benkel";
    $speaker->twitter = "@singlespl";
    $speaker->blog = "http://blog.rbenkel.me";
    $speaker->givePresentation();
    About me

    View Slide

  3. What?

    View Slide

  4. Dependency
    Injection
    Container
    What?

    View Slide

  5. Dependency
    What?

    View Slide

  6. Dependency
    class TwitterAPIClient
    {
    protected $httpClient;
    public function __construct()
    {
    $this->httpClient = new SomeCurlWrapper();
    }
    /* ... */
    }
    $client = new TwitterApiClient;

    View Slide

  7. Dependency
    class TwitterAPIClient
    {
    protected $httpClient;
    public function __construct()
    {
    $this->httpClient = new SomeCurlWrapper();
    }
    /* ... */
    }
    $client = new TwitterApiClient;
    This

    View Slide

  8. “What’s

    View Slide

  9. Try testing it...
    Dependency

    View Slide

  10. ...or change client
    implementation
    Dependency

    View Slide

  11. Dependency

    View Slide

  12. So let’s use Injection
    Dependency

    View Slide

  13. Injection
    What?

    View Slide

  14. Injection
    class TwitterAPIClient
    {
    protected $httpClient;
    public function __construct($httpClient)
    {
    $this->httpClient = $httpClient;
    }
    /* ... */
    }
    $client = new TwitterApiClient(new SomeCurlWrapper);
    And

    View Slide

  15. So...
    Injection

    View Slide

  16. Injection
    public function __construct()
    {
    $this->httpClient = new SomeCurlWrapper();
    }
    public function __construct($httpClient)
    {
    $this->httpClient = $httpClient;
    }
    VS

    View Slide

  17. it’s just like...
    Injection

    View Slide

  18. Injection
    VS

    View Slide

  19. Injection
    VS
    Try

    View Slide

  20. Injection types:
    Injection

    View Slide

  21. Injection types:
    Injection
    • constructor injection

    View Slide

  22. Injection types:
    Injection
    • constructor injection
    • setter injection

    View Slide

  23. Injection types:
    Injection
    • constructor injection
    • setter injection
    • interface injection

    View Slide

  24. Constructor injection
    Injection
    class TwitterAPIClient
    {
    protected $httpClient;
    public function __construct($httpClient)
    {
    $this->httpClient = $httpClient;
    }
    /* ... */
    }
    $client = new TwitterApiClient(new SomeCurlWrapper);

    View Slide

  25. Setter injection
    Injection
    class TwitterAPIClient
    {
    protected $httpClient;
    public function __construct() {}
    public function setHttpClient($httpClient) {
    $this->httpClient = $httpClient;
    }
    /* ... */
    }
    $client = new TwitterApiClient;
    $client->setHttpClient(new SomeCurlWrapper);

    View Slide

  26. Interface injection
    Injection
    interface HttpClientInterface {
    public function setHttpClient($httpClient);
    }
    class TwitterAPIClient implements HttpClientInterface {
    protected $httpClient;
    public function __construct() {}
    public function setHttpClient($httpClient) {
    $this->httpClient = $httpClient;
    }
    /* ... */
    }
    $client = new TwitterApiClient;
    $client->setHttpClient(new SomeCurlWrapper);

    View Slide

  27. So far so good...
    Injection

    View Slide

  28. ...until you don’t have
    to do something like
    that:
    Injection

    View Slide

  29. Injection
    $mapper = new UserMapperEncrypted(
    new UserMapperCached(
    new UserMapperDB(
    new PDO(
    'mysql:host=127.0.0.1',
    'user',
    'password'
    )
    ),
    new RedisCacheAdapter(
    '127.0.0.1:6379'
    )
    ),
    'YourSuperSecretPass'
    );
    $mapper->save(new User('John', 'Doe'));

    View Slide

  30. Injection

    View Slide

  31. Injection
    “How

    View Slide

  32. Just use...
    Injection

    View Slide

  33. Container
    What?

    View Slide

  34. Container
    require_once "container_prod.php";
    $mapper = $container->get('mapper.user');
    /* mapper is UserMapperEncrypted, which uses UserMapperCached,
    which uses UserMapperDB, which uses PDO. */
    $mapper->save(new User('John', 'Doe'));

    View Slide

  35. Container
    require_once "container_dev.php";
    $mapper = $container->get('mapper.user');
    /* mapper is UserMapperDB, with different PDO configuration.
    */
    $mapper->save(new User('John', 'Doe'));

    View Slide

  36. Container
    require_once "container_prod.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));
    require_once "container_dev.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));
    Find

    View Slide

  37. Container
    require_once "container_prod.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));
    require_once "container_dev.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));

    View Slide

  38. Container
    require_once "container_prod.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));
    require_once "container_dev.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));
    Find

    View Slide

  39. Container
    require_once "container_prod.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));
    require_once "container_dev.php";
    $mapper = $container->get('mapper.user');
    $mapper->save(new User('John', 'Doe'));
    Find

    View Slide

  40. So, DIC it’s something
    like:
    Container

    View Slide

  41. Container

    View Slide

  42. What it does:
    Container
    • injects object dependencies
    • creates objects on demand
    • objects could be shared
    • (and sometimes other stuff, like tagging, XML/
    JSON/YAML config etc. )

    View Slide

  43. So. Lets write simple
    one.
    Container

    View Slide

  44. Container
    class Container
    {
    protected $items = array();
    public function get($key) {
    $item = $this->items[$key];
    return is_callable($item) ? $item($this) : $item;
    }
    public function set($key, $value, $shared = false) {
    if ($shared === true && is_callable($value)) {
    $this->items[$key] = function($c) use ($value) {
    static $obj;
    if (!$obj) {
    $obj = $value($c);
    }
    return $obj;
    };
    } else {
    $this->items[$key] = $value;
    }
    }
    }

    View Slide

  45. Container
    class Container
    {
    protected $items = array();
    public function get($key) {
    $item = $this->items[$key];
    return is_callable($item) ? $item($this) : $item;
    }
    public function set($key, $value, $shared = false) {
    if ($shared === true && is_callable($value)) {
    $this->items[$key] = function($c) use ($value) {
    static $obj;
    if (!$obj) {
    $obj = $value($c);
    }
    return $obj;
    };
    } else {
    $this->items[$key] = $value;
    }
    }
    }
    *

    View Slide

  46. Lets use that.
    Injection

    View Slide

  47. Replacing this:
    Injection

    View Slide

  48. Injection
    $mapper = new UserMapperEncrypted(
    new UserMapperCached(
    new UserMapperDB(
    new PDO(
    'mysql:host=127.0.0.1',
    'user',
    'password'
    )
    ),
    new RedisCacheAdapter(
    '127.0.0.1:6379'
    )
    ),
    'YourSuperSecretPass'
    );
    $mapper->save(new User('John', 'Doe'));

    View Slide

  49. with this:
    Injection

    View Slide

  50. Injection
    require_once "container_prod.php";
    $mapper = $container->get('mapper.user');
    /* mapper is UserMapperEncrypted, which uses UserMapperCached
    (using Redis for cache), which uses UserMapperDB, which uses
    PDO. */
    $mapper->save(new User('John', 'Doe'));

    View Slide

  51. Because everything is
    configured in
    container...
    Injection

    View Slide

  52. Injection
    //container_prod.php
    $c = new Container();
    $c->set('pdo.dsn', 'mysql:host=127.0.0.1');
    $c->set('pdo.user', 'user');
    $c->set('pdo.pass', 'password');
    $c->set('redis.host', '127.0.0.1:6379');
    $c->set('mcrypt.key', 'YourSuperSecretPass');
    $c->set('pdo', function(Container $c) {
    return new PDO(
    $c->get('pdo.dsn'),
    $c->get('pdo.user'),
    $c->get('pdo.pass'),
    );
    }, true);
    $c->set('cache.adapter', function(Container $c) {
    return new RedisCacheAdapter($c->get('redis.host'));
    });
    $c->set('mapper.user', function(Container $c) {
    return new UserMapperEncrypted(
    new UserMapperCached(
    new UserMapperDB($c->get('pdo')),
    $c->get('cache.adapter')
    ),
    $c->get('mcrypt.key')
    );
    });

    View Slide

  53. ...you can change e.g
    cache adapter...
    Injection

    View Slide

  54. Injection
    //container_prod.php
    $c = new Container();
    $c->set('pdo.dsn', 'mysql:host=127.0.0.1');
    $c->set('pdo.user', 'user');
    $c->set('pdo.pass', 'password');
    $c->set('mcrypt.key', 'YourSuperSecretPass');
    $c->set('pdo', function(Container $c) {
    return new PDO(
    $c->get('pdo.dsn'),
    $c->get('pdo.user'),
    $c->get('pdo.pass'),
    );
    }, true);
    $c->set('cache.adapter', function(Container $c) {
    return new ApcCacheAdapter();
    });
    $c->set('mapper.user', function(Container $c) {
    return new UserMapperEncrypted(
    new UserMapperCached(
    new UserMapperDB($c->get('pdo')),
    $c->get('cache.adapter')
    ),
    $c->get('mcrypt.key')
    );
    });

    View Slide

  55. Injection
    //container_prod.php
    $c = new Container();
    $c->set('pdo.dsn', 'mysql:host=127.0.0.1');
    $c->set('pdo.user', 'user');
    $c->set('pdo.pass', 'password');
    $c->set('mcrypt.key', 'YourSuperSecretPass');
    $c->set('pdo', function(Container $c) {
    return new PDO(
    $c->get('pdo.dsn'),
    $c->get('pdo.user'),
    $c->get('pdo.pass'),
    );
    }, true);
    $c->set('cache.adapter', function(Container $c) {
    return new ApcCacheAdapter();
    });
    $c->set('mapper.user', function(Container $c) {
    return new UserMapperEncrypted(
    new UserMapperCached(
    new UserMapperDB($c->get('pdo')),
    $c->get('cache.adapter')
    ),
    $c->get('mcrypt.key')
    );
    });

    View Slide

  56. ...and your your code
    hasn’t changed at all.
    Injection

    View Slide

  57. Injection
    require_once "container_prod.php";
    $mapper = $container->get('mapper.user');
    /* mapper is UserMapperEncrypted, which uses UserMapperCached
    (using Apc for cache), which uses UserMapperDB, which uses
    PDO. */
    $mapper->save(new User('John', 'Doe'));

    View Slide

  58. But probably, you
    should use another
    DIC:
    Container

    View Slide

  59. • AuraDI
    http://auraphp.github.com/Aura.Di/
    • Pimple
    http://pimple.sensiolabs.org/
    • Symfony Dependency Injection Component
    http://symfony.com/doc/current/components/dependency_injection/
    introduction.html
    • ZF Dependency Injection
    http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart
    • Twittee
    http://twittee.org/
    Container

    View Slide

  60. • AuraDI
    http://auraphp.github.com/Aura.Di/
    • Pimple
    http://pimple.sensiolabs.org/
    • Symfony Dependency Injection Component
    http://symfony.com/doc/current/components/dependency_injection/
    introduction.html
    • ZF Dependency Injection
    http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart
    • Twittee
    http://twittee.org/
    Container
    PHP

    View Slide

  61. • AuraDI
    http://auraphp.github.com/Aura.Di/
    • Pimple
    http://pimple.sensiolabs.org/
    • Symfony Dependency Injection Component
    http://symfony.com/doc/current/components/dependency_injection/
    introduction.html
    • ZF Dependency Injection
    http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart
    • Twittee
    http://twittee.org/
    Container
    Small,

    View Slide

  62. • AuraDI
    http://auraphp.github.com/Aura.Di/
    • Pimple
    http://pimple.sensiolabs.org/
    • Symfony Dependency Injection Component
    http://symfony.com/doc/current/components/dependency_injection/
    introduction.html
    • ZF Dependency Injection
    http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart
    • Twittee
    http://twittee.org/
    Container
    Lot’s

    View Slide

  63. • AuraDI
    http://auraphp.github.com/Aura.Di/
    • Pimple
    http://pimple.sensiolabs.org/
    • Symfony Dependency Injection Component
    http://symfony.com/doc/current/components/dependency_injection/
    introduction.html
    • ZF Dependency Injection
    http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart
    • Twittee
    http://twittee.org/
    Container
    Fits

    View Slide

  64. Thank you!

    View Slide