PHP 5.3 in practice

10,851
-1

Published on

Published in: Technology
0 Comments
16 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
10,851
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
254
Comments
0
Likes
16
Embeds 0
No embeds

No notes for slide

PHP 5.3 in practice

  1. 1. PHP 5.3 in practice Fabien Potencier PHP 5.3 in practice – Fabien Potencier
  2. 2. Fabien Potencier •  Serial entrepreneur and developer by passion •  Founder of Sensio (in 1998) –  A services and consulting company specialized in Web technologies and Internet marketing (France and USA) –  70 people –  Open-Source specialists –  Big corporate customers –  Consulting, training, development, web design, … and more –  Sponsor of a lot of Open-Source projects like symfony and Doctrine PHP 5.3 in practice – Fabien Potencier
  3. 3. Fabien Potencier •  Creator and lead developer of symfony… •  and creator and lead developer of some more OSS: –  Symfony components –  Swift Mailer : Powerful component based mailing library for PHP –  Twig : Fexible, fast, and secure template language for PHP –  Pirum : Simple PEAR Channel Server Manager –  Sismo : PHP continuous integration server –  Lime : Easy to use unit testing library for PHP –  Twitto : A web framework in a tweet –  Twittee : A Dependency Injection injector in a tweet –  Pimple : A small PHP 5.3 dependency injection injector PHP 5.3 in practice – Fabien Potencier
  4. 4. Fabien Potencier •  Read my technical blog: http://fabien.potencier.org/ •  Follow me on Twitter: @fabpot •  Fork my code on Github: http://github.com/fabpot/ PHP 5.3 in practice – Fabien Potencier
  5. 5. Migrating to PHP 5.3 … for technical reasons PHP 5.3 in practice – Fabien Potencier
  6. 6. Migrating to PHP 5.3? •  Why? – Much faster – Less memory •  When? – PHP 5.3.1 is available – PHP 5.3.2 is about to be released and stable – Migration is simple enough PHP 5.3 in practice – Fabien Potencier
  7. 7. Migrating to PHP 5.3 … for speed PHP 5.3 in practice – Fabien Potencier
  8. 8. Dmitry Stogov did some benchmarks for popular PHP applications Drupal 20% faster Typo3 30% faster Wordpress 15% faster Xoops 10% faster http://news.php.net/php.internals/36484 PHP 5.3 in practice – Fabien Potencier
  9. 9. Doctrine 1.X and 2.0 Faster with PHP 5.3 and less memory consumption 30% less memory 20% faster PHP 5.3 in practice – Fabien Potencier
  10. 10. symfony 1 -47% symfony project running on PHP 5.2 vs PHP 5.3 profiled with XHPROF (run 4aeeb7d54b732 is PHP 5.3) PHP 5.3 in practice – Fabien Potencier
  11. 11. Migrating to PHP 5.3 … for the ecosystem PHP 5.3 in practice – Fabien Potencier
  12. 12. Second generation of PHP frameworks •  The next major versions of the most popular frameworks and libraries will use PHP 5.3 –  Symfony 2.0 –  Doctrine 2.0 Late 2010 –  Zend Framework 2.0 •  Better interoperability between these libraries, thanks to namespaces PHP 5.3 in practice – Fabien Potencier
  13. 13. Namespaces and Symfony 2 SymfonyComponents SymfonyFoundation SymfonyFramework SymfonyComponentsEventDispatcherEvent SymfonyFoundationUniversalClassLoader PHP 5.3 in practice – Fabien Potencier
  14. 14. SymfonyComponentsEventDispatcherEvent vs sfEvent Class names are NOT shorter PHP 5.3 in practice – Fabien Potencier
  15. 15. Namespaces and Symfony 2 require __DIR__.'/lib/Symfony/Core/ClassLoader.php'; use SymfonyFoundationClassLoader; use SymfonyComponentsEventDispatcherEvent; $loader = new ClassLoader('Symfony', __DIR__.'/lib'); $loader->register(); $event = new Event(); PHP 5.3 in practice – Fabien Potencier
  16. 16. Namespaces and Symfony 2 require __DIR__.'/lib/Symfony/Core/ClassLoader.php'; use SymfonyFoundationClassLoader; use SymfonyComponentsEventDispatcherEvent; $loader = new ClassLoader('Symfony', __DIR__.'/lib'); $loader->register(); $event = new Event(); PHP 5.3 in practice – Fabien Potencier
  17. 17. PHP 5.3 technical interoperability standards « … describes the mandatory requirements that must be adhered to for autoloader interoperability » http://groups.google.com/group/php-standards/web/psr-0-final-proposal PHP 5.3 in practice – Fabien Potencier
  18. 18. Why? •  Libraries following the specification are interoperable •  For instance, if you use Symfony 2.0, Doctrine 2.0, and Zend Framework 2.0 in the same project –  They can all share the same autoloader –  Symfony 2.0 provides an enhanced autoloader (with PEAR support) –  A native C extension has been created PHP 5.3 in practice – Fabien Potencier
  19. 19. Let’s dive into PHP 5.3 PHP 5.3 in practice – Fabien Potencier
  20. 20. PHP 5.3 •  A lot of changes –  Convenient changes: __DIR__, ?:, NOWDOC, … –  New features: i18n, SPL, Date management, mysqlnd, … –  Language enhancements: namespaces, anonymous functions, closures, late static binding, phar, Windows support, … PHP 5.3 in practice – Fabien Potencier
  21. 21. PHP 5.3 How does it change the implementation of some well-known Design Pattern? PHP 5.3 in practice – Fabien Potencier
  22. 22. PHP 5.3 … and the Singleton PHP 5.3 in practice – Fabien Potencier
  23. 23. The Singleton may cause serious damage to your code PHP 5.3 in practice – Fabien Potencier
  24. 24. History of the Singleton PHP 5.3 in practice – Fabien Potencier
  25. 25. The Singleton in PHP 4 class Singleton { function &getInstance() { static $instance; if (!$instance) { $instance = new Singleton(); } } return $instance; You can still } ins tantiate the class $obj =& Singleton::getInstance(); directly PHP 5.3 in practice – Fabien Potencier
  26. 26. The Singleton in PHP 5.0/5.1/5.2 class Singleton { static private $instance; private function __construct() {} static public function getInstance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; do not forget to } } final private function __clone() {} ove rride __clone() $obj = Singleton::getInstance(); PHP 5.3 in practice – Fabien Potencier
  27. 27. The Singleton in PHP 5.3 abstract class Singleton { private static $instances = array(); final private function __construct() { if (isset(self::$instances[get_called_class()])) { throw new Exception("An instance of ".get_called_class()." 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() {} } PHP 5.3 in practice – Fabien Potencier
  28. 28. The Singleton in PHP 5.3 class Foo extends Singleton {} class Bar extends Singleton {} $a = Foo::getInstance(); $b = Bar::getInstance(); PHP 5.3 in practice – Fabien Potencier
  29. 29. PHP 5.3 …Late Static Binding The ORM problem PHP 5.3 in practice – Fabien Potencier
  30. 30. class Model { static public function getMe() { return __CLASS__; } } class Article extends Model {} echo Article::getMe(); PHP 5.3 in practice – Fabien Potencier
  31. 31. <?php class Model { static public function getMe() { return get_called_class(); as of PHP 5.3 } } class Article extends Model {} echo Article::getMe(); PHP 5.3 in practice – Fabien Potencier
  32. 32. class Model { static public function findByPk($id) { $table = strtolower(get_called_class()); return $db->get( sprintf('SELECT * FROM %s WHERE id = %d', $table, $id) ); } } class Article extends Model {} $article = Article::findByPk(1); PHP 5.3 in practice – Fabien Potencier
  33. 33. class Model { static public function __callStatic($method, $arguments) { $table = strtolower(get_called_class()); $column = strtolower(substr($method, 6)); $value = $arguments[0]; $sql = sprintf('SELECT * FROM %s WHERE %s = ?', $table, $column); return $db->get($sql, $value); } } class Article extends Model {} $article = Article::findByTitle('foo'); PHP 5.3 in practice – Fabien Potencier
  34. 34. PHP 5.3 …interlude Anonymous functions Lambdas PHP 5.3 in practice – Fabien Potencier
  35. 35. An anonymous function is a function defined on the fly (no name) function () { echo 'Hello world!'; }; PHP 5.3 in practice – Fabien Potencier
  36. 36. Can be stored in a variable $hello = function () { echo 'Hello world!'; }; PHP 5.3 in practice – Fabien Potencier
  37. 37. … to be used later on $hello(); call_user_func($hello); PHP 5.3 in practice – Fabien Potencier
  38. 38. … or can be passed as a function argument function foo(Closure $func) { $func(); } foo($hello); PHP 5.3 in practice – Fabien Potencier
  39. 39. Fonctions anonymes Can take arguments $hello = function ($name) { echo 'Hello '.$name; }; $hello('Fabien'); call_user_func($hello, 'Fabien'); PHP 5.3 in practice – Fabien Potencier
  40. 40. Fonctions anonymes function foo(Closure $func, $name) { $func($name); } foo($hello, 'Fabien'); PHP 5.3 in practice – Fabien Potencier
  41. 41. When is it useful? PHP 5.3 in practice – Fabien Potencier
  42. 42. array_* Greatly simplify usage of some array_* functions array_map() array_reduce() array_filter() PHP 5.3 in practice – Fabien Potencier
  43. 43. class Article { public function __construct($title) { $this->title = $title; } public function getTitle() { return $this->title; } } PHP 5.3 in practice – Fabien Potencier
  44. 44. 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!'), ); PHP 5.3 in practice – Fabien Potencier
  45. 45. $titles = array(); foreach ($articles as $article) { $titles[] = $article->getTitle(); } PHP 5.3 in practice – Fabien Potencier
  46. 46. $titles = array_map( create_function('$article', 'return $article->getTitle();'), $articles ); PHP 5.3 in practice – Fabien Potencier
  47. 47. $titles = array_map( function ($article) { return $article->getTitle(); }, $articles ); PHP 5.3 in practice – Fabien Potencier
  48. 48. $titles = array(); foreach ($articles as $article) { $titles[] = $article->getTitle(); } 100 100 $titles = array_map(create_function('$article', 'return $article->getTitle();'), $articles); 300 1800 $titles = array_map(function ($article) { return $article->getTitle(); }, $articles); 100 200 $mapper = function ($article) { return $article->getTitle(); }; $titles = array_map($mapper, $articles); 100 180 memory speed PHP 5.3 in practice – Fabien Potencier
  49. 49. $mapper = function ($article) { return $article->getTitle(); }; $titles = array_map($mapper, $articles); $mapper = function ($article) { return $article->getAuthor(); }; $authors = array_map($mapper, $articles); PHP 5.3 in practice – Fabien Potencier
  50. 50. A closure is a lambda that remembers the context of its creation… PHP 5.3 in practice – Fabien Potencier
  51. 51. $mapper = function ($method) { return function ($article) use($method) { return $article->$method(); }; }; PHP 5.3 in practice – Fabien Potencier
  52. 52. $method = 'getTitle'; $mapper = function ($article) use($method) { return $article->$method(); }; $method = 'getAuthor'; $titles = array_map($mapper, $articles); PHP 5.3 in practice – Fabien Potencier
  53. 53. $titleMapper = $mapper('getTitle'); $titles = array_map($titleMapper, $articles); $authorMapper = $mapper('getAuthor'); $authors = array_map($authorMapper, $articles); PHP 5.3 in practice – Fabien Potencier
  54. 54. $titles = array_map($mapper('getTitle'), $articles); $authors = array_map($mapper('getAuthor'), $articles); PHP 5.3 in practice – Fabien Potencier
  55. 55. Dependency Injector PHP 5.3 in practice – Fabien Potencier
  56. 56. « Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields. » http://www.picoinjector.org/injection.html PHP 5.3 in practice – Fabien Potencier
  57. 57. Dependency Injection A real world « web » example PHP 5.3 in practice – Fabien Potencier
  58. 58. In most web applications, you need to manage the user preferences –  The user language –  Whether the user is authenticated or not –  The user credentials –  … PHP 5.3 in practice – Fabien Potencier
  59. 59. This can be done with a User object –  setLanguage(), getLanguage() –  setAuthenticated(), isAuthenticated() –  addCredential(), hasCredential() –  ... PHP 5.3 in practice – Fabien Potencier
  60. 60. The User information need to be persisted between HTTP requests We use the PHP session for the Storage PHP 5.3 in practice – Fabien Potencier
  61. 61. class SessionStorage { function __construct($cookieName = 'PHP_SESS_ID') { session_name($cookieName); session_start(); } function set($key, $value) { $_SESSION[$key] = $value; } // ... } PHP 5.3 in practice – Fabien Potencier
  62. 62. 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(); PHP 5.3 in practice – Fabien Potencier
  63. 63. 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 PHP 5.3 in practice – Fabien Potencier
  64. 64. That’s Dependency Injection Nothing more PHP 5.3 in practice – Fabien Potencier
  65. 65. Instead of harcoding the Storage dependency inside the User class constructor Inject the Storage dependency in the User object PHP 5.3 in practice – Fabien Potencier
  66. 66. A Dependency Injector Describes objects and their dependencies Instantiates and configures objects on-demand PHP 5.3 in practice – Fabien Potencier
  67. 67. An injector SHOULD be able to manage ANY PHP object (POPO) The objects MUST not know that they are managed by the injector PHP 5.3 in practice – Fabien Potencier
  68. 68. •  Parameters –  The SessionStorage implementation we want to use (the class name) –  The session name •  Objects –  SessionStorage –  User •  Dependencies –  User depends on a SessionStorage implementation PHP 5.3 in practice – Fabien Potencier
  69. 69. Let’s build a simple injector with PHP 5.3 PHP 5.3 in practice – Fabien Potencier
  70. 70. Dependency Injector Managing parameters PHP 5.3 in practice – Fabien Potencier
  71. 71. class Injector { protected $parameters = array(); public function setParameter($key, $value) { $this->parameters[$key] = $value; } public function getParameter($key) { return $this->parameters[$key]; } } PHP 5.3 in practice – Fabien Potencier
  72. 72. Decoupling $injector = new Injector(); Customization $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); Objects creation PHP 5.3 in practice – Fabien Potencier
  73. 73. class Injector Using PHP { magic methods protected $parameters = array(); public function __set($key, $value) { $this->parameters[$key] = $value; } public function __get($key) { return $this->parameters[$key]; } } PHP 5.3 in practice – Fabien Potencier
  74. 74. Interface is cleaner $injector = new Injector(); $injector->session_name = 'SESSION_ID'; $injector->storage_class = 'SessionStorage'; $sessionStorage = new $injector->storage_class($injector->session_name); $user = new User($sessionStorage); PHP 5.3 in practice – Fabien Potencier
  75. 75. Dependency Injector Managing objects PHP 5.3 in practice – Fabien Potencier
  76. 76. We need a way to describe how to create objects, without actually instantiating anything! Anonymous functions to the rescue! PHP 5.3 in practice – Fabien Potencier
  77. 77. class Injector { protected $parameters = array(); protected $objects = array(); public function __set($key, $value) { $this->parameters[$key] = $value; } public function __get($key) Store a lambda { return $this->parameters[$key]; able to create the object on-demand } public function setService($key, Closure $service) { $this->objects[$key] = $service; } public function getService($key) Ask the closure to create { return $this->objects[$key]($this); th e object and pass the } } current injector PHP 5.3 in practice – Fabien Potencier
  78. 78. $injector = new Injector(); $injector->session_name = 'SESSION_ID'; Description $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); }); Creating the User is now as easy as before $user = $injector->getService('user'); PHP 5.3 in practice – Fabien Potencier
  79. 79. class Injector { protected $values = array(); Simplify the code function __set($id, $value) { $this->values[$id] = $value; } function __get($id) { if (is_callable($this->values[$id])) { return $this->values[$id]($this); } else { return $this->values[$id]; } } } PHP 5.3 in practice – Fabien Potencier
  80. 80. $injector = new Injector(); Unified interface $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; PHP 5.3 in practice – Fabien Potencier
  81. 81. Dependency Injector Scope PHP 5.3 in practice – Fabien Potencier
  82. 82. For some objects, like the user, the injector must always return the same instance PHP 5.3 in practice – Fabien Potencier
  83. 83. spl_object_hash($injector->user) !== spl_object_hash($injector->user) PHP 5.3 in practice – Fabien Potencier
  84. 84. $injector->user = function ($c) { static $user; if (is_null($user)) { $user = new User($c->storage); } return $user; }; PHP 5.3 in practice – Fabien Potencier
  85. 85. spl_object_hash($injector->user) === spl_object_hash($injector->user) PHP 5.3 in practice – Fabien Potencier
  86. 86. $injector->user = $injector->asShared(function ($c) { return new User($c->storage); }); PHP 5.3 in practice – Fabien Potencier
  87. 87. function asShared(Closure $lambda) { return function ($injector) use ($lambda) { static $object; if (is_null($object)) { $object = $lambda($injector); } return $object; }; } PHP 5.3 in practice – Fabien Potencier
  88. 88. class Injector { 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]; } } } PHP 5.3 in practice – Fabien Potencier
  89. 89. 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) { 40 LOC for a fully- return function ($c) use ($callable) { static $object; if (is_null($object)) { $object = $callable($c); featured injector } return $object; }; } } PHP 5.3 in practice – Fabien Potencier
  90. 90. I’m NOT advocating the usage of lambdas everywhere This presentation was about showing how they work on practical examples PHP 5.3 in practice – Fabien Potencier
  91. 91. Questions? PHP 5.3 in practice – Fabien Potencier
  92. 92. 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/ PHP 5.3 in practice – Fabien Potencier
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×