1. PHP 5.3 in practice
Fabien Potencier
PHP 5.3 in practice – Fabien Potencier
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. 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. 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. Migrating to PHP 5.3
… for technical reasons
PHP 5.3 in practice – Fabien Potencier
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. Migrating to PHP 5.3
… for speed
PHP 5.3 in practice – Fabien Potencier
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. 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. 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. Migrating to PHP 5.3
… for the ecosystem
PHP 5.3 in practice – Fabien Potencier
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. Namespaces and Symfony 2
SymfonyComponents
SymfonyFoundation
SymfonyFramework
SymfonyComponentsEventDispatcherEvent
SymfonyFoundationUniversalClassLoader
PHP 5.3 in practice – Fabien Potencier
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. 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. 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. 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. Let’s dive into PHP 5.3
PHP 5.3 in practice – Fabien Potencier
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. PHP 5.3
How does it change the implementation
of some well-known Design Pattern?
PHP 5.3 in practice – Fabien Potencier
22. PHP 5.3
… and the Singleton
PHP 5.3 in practice – Fabien Potencier
23. The Singleton may cause
serious damage
to your code
PHP 5.3 in practice – Fabien Potencier
24. History of the Singleton
PHP 5.3 in practice – Fabien Potencier
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. 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. 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. 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. PHP 5.3
…Late Static Binding
The ORM problem
PHP 5.3 in practice – Fabien Potencier
30. class Model
{
static public function getMe()
{
return __CLASS__;
}
}
class Article extends Model {}
echo Article::getMe();
PHP 5.3 in practice – Fabien Potencier
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. 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. 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
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. Can be stored in a variable
$hello = function () { echo 'Hello world!'; };
PHP 5.3 in practice – Fabien Potencier
37. … to be used later on
$hello();
call_user_func($hello);
PHP 5.3 in practice – Fabien Potencier
38. … or can be passed as a function argument
function foo(Closure $func)
{
$func();
}
foo($hello);
PHP 5.3 in practice – Fabien Potencier
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
41. When is it useful?
PHP 5.3 in practice – Fabien Potencier
42. array_*
Greatly simplify usage of some array_* functions
array_map()
array_reduce()
array_filter()
PHP 5.3 in practice – Fabien Potencier
43. class Article
{
public function __construct($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
}
PHP 5.3 in practice – Fabien Potencier
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. $titles = array();
foreach ($articles as $article)
{
$titles[] = $article->getTitle();
}
PHP 5.3 in practice – Fabien Potencier
46. $titles = array_map(
create_function('$article', 'return $article->getTitle();'),
$articles
);
PHP 5.3 in practice – Fabien Potencier
47. $titles = array_map(
function ($article) { return $article->getTitle(); },
$articles
);
PHP 5.3 in practice – Fabien Potencier
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
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. This can be done with a User object
– setLanguage(), getLanguage()
– setAuthenticated(), isAuthenticated()
– addCredential(), hasCredential()
– ...
PHP 5.3 in practice – Fabien Potencier
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. 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. 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. 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
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. A Dependency Injector
Describes objects
and their dependencies
Instantiates and configures
objects on-demand
PHP 5.3 in practice – Fabien Potencier
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. • 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. Let’s build a simple injector
with PHP 5.3
PHP 5.3 in practice – Fabien Potencier
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. 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. 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. 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
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. 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. $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. 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. $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
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. 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. 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. 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