introduction to di(c)

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

Upload: radek-benkel

Post on 11-Nov-2014

1.974 views

Category:

Technology


3 download

DESCRIPTION

Quick introduction to Dependency Injection (Container).

TRANSCRIPT

Page 1: Introduction to DI(C)

Introduction to DI(C)

meet.php #! "#.$!.%$"%http://meetphp.pl/

Page 2: Introduction to DI(C)

$speaker = new Speaker;

$speaker->name = "Radosław Benkel";$speaker->twitter = "@singlespl";$speaker->blog = "http://blog.rbenkel.me";

$speaker->givePresentation();

About me

Page 3: Introduction to DI(C)

What?

Page 4: Introduction to DI(C)

DependencyInjectionContainer

What?

Page 5: Introduction to DI(C)

Dependency

What?

Page 6: Introduction to DI(C)

Dependency

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

$client = new TwitterApiClient;

Page 7: Introduction to DI(C)

Dependency

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

$client = new TwitterApiClient;

This����������� ������������������  is����������� ������������������  your����������� ������������������  dependency.

Page 8: Introduction to DI(C)

“What’s����������� ������������������  wrong����������� ������������������  with����������� ������������������  that”?

Dependency

Page 9: Introduction to DI(C)

Try testing it...

Dependency

Page 10: Introduction to DI(C)

...or change client implementation

Dependency

Page 11: Introduction to DI(C)

Dependency

Page 12: Introduction to DI(C)

So let’s use Injection

Dependency

Page 13: Introduction to DI(C)

Injection

What?

Page 14: Introduction to DI(C)

Injection

class TwitterAPIClient{ protected $httpClient; public function __construct($httpClient) { $this->httpClient = $httpClient; } /* ... */}

$client = new TwitterApiClient(new SomeCurlWrapper);

And����������� ������������������  here����������� ������������������  you����������� ������������������  inject����������� ������������������  dependency

Page 15: Introduction to DI(C)

So...

Injection

Page 16: Introduction to DI(C)

Injection

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

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

VS

Page 17: Introduction to DI(C)

it’s just like...

Injection

Page 18: Introduction to DI(C)

Injection

VS

Page 19: Introduction to DI(C)

Injection

VS

Try����������� ������������������  replacing����������� ������������������  battery,����������� ������������������  and����������� ������������������  you����������� ������������������  will����������� ������������������  now����������� ������������������  what����������� ������������������  I’m����������� ������������������  talking����������� ������������������  about.����������� ������������������  

Page 20: Introduction to DI(C)

Injection types:

Injection

Page 21: Introduction to DI(C)

Injection types:

Injection

• constructor injection

Page 22: Introduction to DI(C)

Injection types:

Injection

• constructor injection• setter injection

Page 23: Introduction to DI(C)

Injection types:

Injection

• constructor injection• setter injection• interface injection

Page 24: Introduction to DI(C)

Constructor injection

Injection

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

Page 25: Introduction to DI(C)

Setter injection

Injection

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

Page 26: Introduction to DI(C)

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

Page 27: Introduction to DI(C)

So far so good...

Injection

Page 28: Introduction to DI(C)

...until you don’t have to do something like

that:

Injection

Page 29: Introduction to DI(C)

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'));

Page 30: Introduction to DI(C)

Injection

Page 31: Introduction to DI(C)

Injection

“How����������� ������������������  to����������� ������������������  solve����������� ������������������  that”?

Page 32: Introduction to DI(C)

Just use...

Injection

Page 33: Introduction to DI(C)

Container

What?

Page 34: Introduction to DI(C)

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'));

Page 35: Introduction to DI(C)

Container

require_once "container_dev.php";

$mapper = $container->get('mapper.user');

/* mapper is UserMapperDB, with different PDO configuration. */$mapper->save(new User('John', 'Doe'));

Page 36: Introduction to DI(C)

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����������� ������������������  the����������� ������������������  difference

Page 37: Introduction to DI(C)

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'));

Page 38: Introduction to DI(C)

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����������� ������������������  the����������� ������������������  differenceConfigures����������� ������������������  services����������� ������������������  in����������� ������������������  different����������� ������������������  way,����������� ������������������  but����������� ������������������  for����������� ������������������  you,����������� ������������������  API����������� ������������������  for����������� ������������������  mapper����������� ������������������  is����������� ������������������  the����������� ������������������  same.

Page 39: Introduction to DI(C)

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����������� ������������������  the����������� ������������������  difference*����������� ������������������  Assuming,����������� ������������������  that����������� ������������������  all����������� ������������������  mappers����������� ������������������  share����������� ������������������  the����������� ������������������  same����������� ������������������  interface,����������� ������������������  which����������� ������������������  they����������� ������������������  rather����������� ������������������  should.

Page 40: Introduction to DI(C)

So, DIC it’s something like:

Container

Page 41: Introduction to DI(C)

Container

Page 42: Introduction to DI(C)

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. )

Page 43: Introduction to DI(C)

So. Lets write simple one.

Container

Page 44: Introduction to DI(C)

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

Page 45: Introduction to DI(C)

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

*����������� ������������������  Inspired����������� ������������������  by����������� ������������������  Pimple

Page 46: Introduction to DI(C)

Lets use that.

Injection

Page 47: Introduction to DI(C)

Replacing this:

Injection

Page 48: Introduction to DI(C)

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'));

Page 49: Introduction to DI(C)

with this:

Injection

Page 50: Introduction to DI(C)

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'));

Page 51: Introduction to DI(C)

Because everything is configured in container...

Injection

Page 52: Introduction to DI(C)

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')

);});

Page 53: Introduction to DI(C)

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

Injection

Page 54: Introduction to DI(C)

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

Page 55: Introduction to DI(C)

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

Page 56: Introduction to DI(C)

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

Injection

Page 57: Introduction to DI(C)

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'));

Page 58: Introduction to DI(C)

But probably, you should use another

DIC:

Container

Page 60: Introduction to DI(C)

• AuraDIhttp://auraphp.github.com/Aura.Di/

• Pimplehttp://pimple.sensiolabs.org/

• Symfony % Dependency Injection Componenthttp://symfony.com/doc/current/components/dependency_injection/introduction.html

• ZF% Dependency Injectionhttp://framework.zend.com/wiki/display/ZFDEV%/Zend+DI+QuickStart

• Twitteehttp://twittee.org/

Container

PHP����������� ������������������  5.4����������� ������������������  only

Page 61: Introduction to DI(C)

• AuraDIhttp://auraphp.github.com/Aura.Di/

• Pimplehttp://pimple.sensiolabs.org/

• Symfony % Dependency Injection Componenthttp://symfony.com/doc/current/components/dependency_injection/introduction.html

• ZF% Dependency Injectionhttp://framework.zend.com/wiki/display/ZFDEV%/Zend+DI+QuickStart

• Twitteehttp://twittee.org/

Container

Small,����������� ������������������  basic

Page 62: Introduction to DI(C)

• AuraDIhttp://auraphp.github.com/Aura.Di/

• Pimplehttp://pimple.sensiolabs.org/

• Symfony % Dependency Injection Componenthttp://symfony.com/doc/current/components/dependency_injection/introduction.html

• ZF% Dependency Injectionhttp://framework.zend.com/wiki/display/ZFDEV%/Zend+DI+QuickStart

• Twitteehttp://twittee.org/

Container

Lot’s����������� ������������������  of����������� ������������������  features

Page 63: Introduction to DI(C)

• AuraDIhttp://auraphp.github.com/Aura.Di/

• Pimplehttp://pimple.sensiolabs.org/

• Symfony % Dependency Injection Componenthttp://symfony.com/doc/current/components/dependency_injection/introduction.html

• ZF% Dependency Injectionhttp://framework.zend.com/wiki/display/ZFDEV%/Zend+DI+QuickStart

• Twitteehttp://twittee.org/

Container

Fits����������� ������������������  into����������� ������������������  tweet!

Page 64: Introduction to DI(C)

Thank you!