design patterns revisited with php 5.3
DESCRIPTION
TRANSCRIPT
![Page 1: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/1.jpg)
Design patterns… revisited for PHP 5.3 Fabien Potencier
http://www.flickr.com/photos/revivaling/4979552548
![Page 2: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/2.jpg)
Serial entrepreneur Developer by passion Founder of Sensio Creator and lead developer of Symfony
http://www.twitter.com/fabpot http://www.github.com/fabpot http://fabien.potencier.org/
![Page 3: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/3.jpg)
How does PHP 5.3 change the implementation of some well-known Design Patterns?
http://www.flickr.com/photos/revivaling/4978949121
![Page 4: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/4.jpg)
http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29
« A design pattern is a general reusable solution to a commonly occurring problem »
![Page 5: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/5.jpg)
http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29
« By definition, a pattern must be programmed anew into each application that uses it. »
![Page 6: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/6.jpg)
![Page 7: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/7.jpg)
The Singleton
http://www.flickr.com/photos/revivaling/4979546114
![Page 8: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/8.jpg)
The Singleton may cause serious damage to your code!
http://www.flickr.com/photos/mattbell/1696868871
![Page 9: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/9.jpg)
class Singleton { function &getInstance() { static $instance;
if (!$instance) { $instance = new Singleton(); }
return $instance; } }
$obj =& Singleton::getInstance();
You can still
instantiate the class directly
The Singleton and PHP 4
![Page 10: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/10.jpg)
class Singleton { static private $instance;
private function __construct() {}
static public function getInstance() { if (null === self::$instance) { self::$instance = new self(); }
return self::$instance; }
final private function __clone() {} }
$obj = Singleton::getInstance();
do not forget to
override __clone()
The Singleton and PHP 5.0/5.1/5.2
![Page 11: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/11.jpg)
abstract class Singleton { private static $instances = array();
final private function __construct() { if (isset(self::$instances[get_called_class()])) { throw new Exception("A ".get_called_class()." instance already exists."); } static::initialize(); }
protected function initialize() {}
final public static function getInstance() { $class = get_called_class(); if (!isset(self::$instances[$class])) { self::$instances[$class] = new static(); } return self::$instances[$class]; }
final private function __clone() {} }
The Singleton and PHP 5.3
![Page 12: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/12.jpg)
class Foo extends Singleton {} class Bar extends Singleton {}
$a = Foo::getInstance(); $b = Bar::getInstance();
The Singleton and PHP 5.3
![Page 13: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/13.jpg)
Active Record …Late Static Binding
http://www.flickr.com/photos/revivaling/4979548952
![Page 14: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/14.jpg)
$article = Article::findByPk(1);
$article = Article::findByTitleAndAuthorId('foo', 1);
![Page 15: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/15.jpg)
class Model { static public function getMe() { return __CLASS__; } }
class Article extends Model {}
echo Article::getMe();
![Page 16: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/16.jpg)
class Model { static public function getMe() { return get_called_class(); } }
class Article extends Model {}
echo Article::getMe();
![Page 17: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/17.jpg)
class Model { static public function findByPk($id) { $table = strtolower(get_called_class()); $sql = "SELECT * FROM $this->table WHERE id = ?";
return $this->db->get($sql, $id); } }
class Article extends Model {}
$article = Article::findByPk(1);
![Page 18: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/18.jpg)
class Model { static public function __callStatic($method, $arguments) { $table = strtolower(get_called_class()); $column = strtolower(substr($method, 6)); $value = $arguments[0];
$sql = "SELECT * FROM $this->table WHERE $column = ?";
return $this->db->get($sql, $value); } }
class Article extends Model {}
$article = Article::findByTitle('foo');
![Page 19: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/19.jpg)
This is pseudo code with no proper SQL Injection protection!
http://www.flickr.com/photos/zippy/22748510
![Page 20: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/20.jpg)
The Observer Pattern
http://www.flickr.com/photos/revivaling/4978951341
![Page 21: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/21.jpg)
The Observer pattern allows to extend or change the behavior of classes without having to change them
![Page 22: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/22.jpg)
When a method is called on an object (subject), it notifies other objects (listeners) of the event
![Page 23: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/23.jpg)
A Dispatcher is an object that manages connections between subjects and listeners
![Page 24: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/24.jpg)
class User { function setLanguage($language) { $this->language = $language; } }
class Translator { function setLanguage($language) { $this->language = $language; } }
![Page 25: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/25.jpg)
Dispatcher Listeners
Translator listens to ’language_change’
User notifies ‘language_change’
Notifiers
1
2 Calls all listeners
Translator callback is called
![Page 26: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/26.jpg)
Dispatcher Listeners
Translator listens to ’language_change’
User notifies ‘language_change’
Notifiers
1
2 Calls all listeners
Translator callback is called
Your class listens to ‘language_change’
Your class callback is called
![Page 27: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/27.jpg)
$dispatcher = new Dispatcher();
$translator = new Translator($dispatcher);
$user = new User($dispatcher);
$user->setLanguage('fr');
![Page 28: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/28.jpg)
class Translator { public function __construct($dispatcher) { $listener = array($translator, 'listenLanguageChange');
$dispatcher->connect('language_change', $listener); }
public function listenLanguageChangeEvent($arguments) { $this->setLanguage($arguments['language']); } }
A PHP callable
The Event name
![Page 29: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/29.jpg)
class User { function setLanguage($language) { $this->language = $language;
$this->dispatcher->notify('language_change', array('language' => $language)); } }
![Page 30: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/30.jpg)
// register the listener with the dispatcher $dispatcher = new Dispatcher(array( 'foo' => $listener, ));
// notify the event anywhere $dispatcher->notify( 'foo', array('name' => 'Fabien') );
A listener can be any PHP callable
![Page 31: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/31.jpg)
class Dispatcher { function __construct($map) { $this->map = $map; }
function notify($name, $args = array()) { call_user_func($this->map[$name], $args); } }
A PHP callable
![Page 32: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/32.jpg)
class Dispatcher { function __construct($map) { $this->map = $map; }
function notify($name, $args = array()) { $this->map[$name]($rags); } } An anonymous function
![Page 33: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/33.jpg)
// a function function foo($args) { echo "Hello {$args['name']}\n"; };
$listener = 'foo';
![Page 34: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/34.jpg)
// an anonymous function $listener = function ($args) { echo "Hello {$args['name']}\n"; };
![Page 35: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/35.jpg)
// register the listener with the dispatcher $dispatcher = new Dispatcher(array( 'foo' => function ($args) { echo "Hello {$args['name']}\n"; }, ));
// notify the event anywhere $dispatcher->notify( 'foo', array('name' => 'Fabien') );
![Page 36: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/36.jpg)
$dispatcher = new Dispatcher(array( 'foo' => $listener ));
![Page 37: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/37.jpg)
class Dispatcher { function connect($name, $listener) { if (!isset($this->map[$name])) { $this->map[$name] = array(); }
$this->map[$name][] = $listener; } }
![Page 38: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/38.jpg)
$l1 = function ($args) { echo "Hello1 {$args['name']}?\n"; };
$l2 = function ($args) { echo "Hello2 {$args['name']}?\n"; };
![Page 39: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/39.jpg)
$listener = new Listeners($l1, $l2);
$dispatcher = new Dispatcher(array( 'foo' => $listener ));
$dispatcher = new Dispatcher(array( 'foo' => new Listeners($l1, $l2) ));
![Page 40: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/40.jpg)
$listener = new Listeners($l1, $l2);
$listeners($args);
![Page 41: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/41.jpg)
class Listeners { function __construct() { $this->listeners = func_get_args(); }
function __invoke($args = array()) { foreach ($this->listeners as $listener) { $listener($args); } } }
Makes the object callable
![Page 42: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/42.jpg)
Template View
http://www.flickr.com/photos/revivaling/4979557230
![Page 43: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/43.jpg)
Hello {{ name }}
![Page 44: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/44.jpg)
echo render('Hello {{ name }}!', array('name' => 'Fabien'));
echo render( file_get_contents(__DIR__.'/template.php'), array('name' => 'Fabien') );
![Page 45: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/45.jpg)
function render($template, $arguments) { $evaluator = function ($match) use ($arguments) { if (isset($arguments[$match[1]])) { return $arguments[$match[1]]; }
return $match[1]; };
return preg_replace_callback('/\{\{\s*(.+?)\s*\}\}/', $evaluator, $template); }
![Page 46: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/46.jpg)
Dependency Injector
http://www.flickr.com/photos/revivaling/4978942907
![Page 47: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/47.jpg)
http://www.picoinjector.org/injection.html
« Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields »
![Page 48: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/48.jpg)
In most web applications, you need to manage the user preferences
– The user language – Whether the user is authenticated or not – …
This can be done with a User object
– setLanguage(), getLanguage() – setAuthenticated(), isAuthenticated() – …
![Page 49: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/49.jpg)
The User information need to be persisted
between HTTP requests
We use the PHP session for the Storage
![Page 50: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/50.jpg)
class SessionStorage { function __construct($cookieName = 'PHP_SESS_ID') { session_name($cookieName); session_start(); }
function set($key, $value) { $_SESSION[$key] = $value; }
// ... }
![Page 51: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/51.jpg)
class User { protected $storage;
function __construct() { $this->storage = new SessionStorage(); }
function setLanguage($language) { $this->storage->set('language', $language); }
// ... }
$user = new User();
Very easy to use
Very hard to
customize
![Page 52: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/52.jpg)
class User { protected $storage;
function __construct($storage) { $this->storage = $storage; } }
$storage = new SessionStorage(); $user = new User($storage);
Slightly more
difficult to use
Very easy to
customize
![Page 53: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/53.jpg)
That’s Dependency Injection
Nothing more
![Page 54: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/54.jpg)
Instead of harcoding the Storage dependency
inside the User class constructor
Inject the Storage dependency in the User object
![Page 55: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/55.jpg)
A Dependency Injector
Describes objects and their dependencies
Instantiates and configures objects on-demand
![Page 56: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/56.jpg)
An injector SHOULD be able to manage
ANY PHP object (POPO)
The objects MUST not know that they are managed
by the injector
![Page 57: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/57.jpg)
• Parameters – The SessionStorage implementation we want to use (the class name) – The session name
• Objects – SessionStorage – User
• Dependencies – User depends on a SessionStorage implementation
![Page 58: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/58.jpg)
Let’s build a simple injector with PHP 5.3
http://www.flickr.com/photos/22750018@N05/4531762220/
![Page 59: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/59.jpg)
Dependency Injector: Parameters
http://www.flickr.com/photos/revivaling/4979546964
![Page 60: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/60.jpg)
class Injector { protected $parameters = array();
public function setParameter($key, $value) { $this->parameters[$key] = $value; }
public function getParameter($key) { return $this->parameters[$key]; } }
![Page 61: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/61.jpg)
$injector = new Injector(); $injector->setParameter('session_name', 'SESSION_ID'); $injector->setParameter('storage_class', 'SessionStorage');
$class = $injector->getParameter('storage_class'); $sessionStorage = new $class($injector->getParameter('session_name')); $user = new User($sessionStorage);
Decoupling
Customization
Objects creation
![Page 62: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/62.jpg)
class Injector { protected $parameters = array();
public function __set($key, $value) { $this->parameters[$key] = $value; }
public function __get($key) { return $this->parameters[$key]; } }
Using PHP
magic methods
![Page 63: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/63.jpg)
$injector = new Injector(); $injector->session_name = 'SESSION_ID'; $injector->storage_class = 'SessionStorage';
$sessionStorage = new $injector->storage_class($injector->session_name); $user = new User($sessionStorage);
Interface
is cleaner
![Page 64: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/64.jpg)
Dependency Injector: Objects
http://www.flickr.com/photos/revivaling/4979547636
![Page 65: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/65.jpg)
We need a way to describe how to create objects, without actually instantiating anything!
Anonymous functions to the rescue!
![Page 66: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/66.jpg)
class Injector { protected $parameters = array(); protected $objects = array();
public function __set($key, $value) { $this->parameters[$key] = $value; }
public function __get($key) { return $this->parameters[$key]; }
public function setService($key, Closure $service) { $this->objects[$key] = $service; }
public function getService($key) { return $this->objects[$key]($this); } }
Store a lambda
able to create the
object on-demand
Ask the closure to create
the object and pass the
current injector
![Page 67: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/67.jpg)
$injector = new Injector(); $injector->session_name = 'SESSION_ID'; $injector->storage_class = 'SessionStorage'; $injector->setService('user', function ($c) { return new User($c->getService('storage')); }); $injector->setService('storage', function ($c) { return new $c->storage_class($c->session_name); });
$user = $injector->getService('user');
Creating the User
is now as easy as before
Description
![Page 68: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/68.jpg)
class Injector { 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]; } } }
Simplify the code
![Page 69: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/69.jpg)
$injector = new Injector(); $injector->session_name = 'SESSION_ID'; $injector->storage_class = 'SessionStorage'; $injector->user = function ($c) { return new User($c->storage); }; $injector->storage = function ($c) { return new $c->storage_class($c->session_name); };
$user = $injector->user;
Unified interface
![Page 70: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/70.jpg)
Dependency Injector: Scope
http://www.flickr.com/photos/revivaling/4979545016
![Page 71: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/71.jpg)
For some objects, like the user, the injector must always return the same instance
![Page 72: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/72.jpg)
spl_object_hash($injector->user)
!==
spl_object_hash($injector->user)
![Page 73: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/73.jpg)
$injector->user = function ($c) { static $user;
if (is_null($user)) { $user = new User($c->storage); }
return $user; };
![Page 74: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/74.jpg)
spl_object_hash($injector->user)
===
spl_object_hash($injector->user)
![Page 75: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/75.jpg)
$injector->user = $injector->asShared(function ($c) { return new User($c->storage); });
![Page 76: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/76.jpg)
function asShared(Closure $lambda) { return function ($injector) use ($lambda) { static $object;
if (is_null($object)) { $object = $lambda($injector); }
return $object; }; }
![Page 77: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/77.jpg)
class Injector { 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]; } } }
Error management
![Page 78: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/78.jpg)
class Injector { 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)) { $object = $callable($c); } return $object; }; } }
40 LOC for a fully-
featured injector
![Page 79: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/79.jpg)
Twittee: A Dependency Injection Container in a tweet
• Implementation does not use PHP 5.3 • Its usage needs PHP 5.3
class Container { protected $s=array(); function __set($k, $c) { $this->s[$k]=$c; } function __get($k) { return $this->s[$k]($this); } }
twittee.org
![Page 80: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/80.jpg)
Anonymous Functions Closures
Late Static Binding __invoke()
…
![Page 81: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/81.jpg)
I’m NOT advocating the usage of lambdas everywhere
This presentation was about showing how they work
on practical examples
![Page 82: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/82.jpg)
Questions?
![Page 83: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/83.jpg)
![Page 84: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/84.jpg)
Sensio S.A. 92-98, boulevard Victor Hugo
92 115 Clichy Cedex FRANCE
Tél. : +33 1 40 99 80 80
Contact Fabien Potencier
fabien.potencier at sensio.com
http://www.sensiolabs.com/
http://www.symfony-project.org/
http://fabien.potencier.org/
![Page 85: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/85.jpg)
Interlude …Anonymous Functions
http://www.flickr.com/photos/gregory_bastien/2565132371
![Page 86: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/86.jpg)
An anonymous function is a function
defined on the fly (no name)
function () { echo 'Hello world!'; };
![Page 87: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/87.jpg)
Can be stored in a variable
$hello = function () { echo 'Hello world!'; };
![Page 88: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/88.jpg)
… to be used later on
$hello();
call_user_func($hello);
![Page 89: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/89.jpg)
… or can be passed as a function argument
function foo(Closure $func) { $func(); }
foo($hello);
![Page 90: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/90.jpg)
Fonctions anonymes
$hello = function ($name) { echo 'Hello '.$name; };
$hello('Fabien');
call_user_func($hello, 'Fabien');
Can take arguments
![Page 91: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/91.jpg)
Fonctions anonymes
function foo(Closure $func, $name) { $func($name); }
foo($hello, 'Fabien');
![Page 92: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/92.jpg)
When is it useful?
![Page 93: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/93.jpg)
array_*
Greatly simplify usage of some array_* functions
array_map()
array_reduce()
array_filter()
![Page 94: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/94.jpg)
class Article { public function __construct($title) { $this->title = $title; }
public function getTitle() { return $this->title; } }
![Page 95: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/95.jpg)
How to get an array of all article titles?
$articles = array( new Article('PHP UK - part 1'), new Article('PHP UK - part 2'), new Article('See you next year!'), );
![Page 96: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/96.jpg)
$titles = array(); foreach ($articles as $article) { $titles[] = $article->getTitle(); }
![Page 97: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/97.jpg)
$titles = array_map( create_function('$article', 'return $article->getTitle();'), $articles );
![Page 98: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/98.jpg)
$titles = array_map( function ($article) { return $article->getTitle(); }, $articles );
![Page 99: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/99.jpg)
$titles = array(); foreach ($articles as $article) { $titles[] = $article->getTitle(); }
100 100
$titles = array_map(create_function('$article', 'return $article->getTitle();'), $articles);
1800 300
$titles = array_map(function ($article) { return $article->getTitle(); }, $articles);
200 100
memory speed
$mapper = function ($article) { return $article->getTitle(); }; $titles = array_map($mapper, $articles);
180 100
![Page 100: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/100.jpg)
$mapper = function ($article) { return $article->getTitle(); };
$titles = array_map($mapper, $articles);
$mapper = function ($article) { return $article->getAuthor(); };
$authors = array_map($mapper, $articles);
![Page 101: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/101.jpg)
A closure is a lambda that remembers the context
of its creation…
![Page 102: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/102.jpg)
$mapper = function ($method) { return function ($article) use($method) { return $article->$method(); }; };
![Page 103: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/103.jpg)
$method = 'getTitle';
$mapper = function ($article) use($method) { return $article->$method(); };
$method = 'getAuthor';
$titles = array_map($mapper, $articles);
![Page 104: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/104.jpg)
$titleMapper = $mapper('getTitle'); $titles = array_map($titleMapper, $articles);
$authorMapper = $mapper('getAuthor'); $authors = array_map($authorMapper, $articles);
![Page 105: Design patterns revisited with PHP 5.3](https://reader033.vdocument.in/reader033/viewer/2022042601/540e1a5a8d7f728d7e8b4bb5/html5/thumbnails/105.jpg)
$titles = array_map($mapper('getTitle'), $articles);
$authors = array_map($mapper('getAuthor'), $articles);