Playing With PHP 5.3
-
Upload
fabien-potencier -
Category
Technology
-
view
6.622 -
download
3
description
Transcript of Playing With PHP 5.3
Jouons avec PHP 5.3
Fabien Potencier
Fabien Potencier • Serial entrepreneur et développeur par passion • Fondateur de Sensio (1998)
– Société de conseil autour des technologies Open-Source (France and USA)
– 70 personnes – Clients grands comptes – Sponsor de projets Open-Source
comme Symfony, Doctrine ou Swift Mailer
Fabien Potencier
• Mon blog technique : http://fabien.potencier.org/
• Sur Twitter : http://www.twitter.com/fabpot
• Mon code sur Github: http://github.com/fabpot/
Migrer vers PHP 5.3 Des raisons techniques
Migrer vers PHP 5.3 ?
• Pourquoi ? – Plus rapide – Moins de mémoire
• Quand ? – PHP 5.3.0 est déjà stable depuis quelques mois – PHP 5.3.1 va bientôt être disponible – La migration est simple
PHP 5.3 Beaucoup plus rapide ?
Dmitry Stogov a fait quelques tests de performance pour des applications PHP connues
Drupal 20% faster
Typo3 30% faster
Wordpress 15% faster
Xoops 10% faster
http://news.php.net/php.internals/36484
Doctrine 1.X and 2.0
Significativement plus rapide avec PHP 5.3
30% de mémoire en moins
20% plus rapide
symfony 1.X
symfony project running on PHP 5.2 vs PHP 5.3 profiled with XHPROF (run 4aeeb7d54b732 is PHP 5.3)
-47%
Migrer vers PHP 5.3 Des raisons fonctionnelles
Migrer vers PHP 5.3, frameworks 2.0
• Prochaines versions des principaux frameworks/bibliothèques seront basés sur PHP 5.3
– Symfony 2.0 – Doctrine 2.0 – Zend Framework 2.0
• Interopérabilité améliorée entre ces bibliothèques, grâce aux namespaces
Fin 2010
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/final-proposal
Pourquoi ?
• Les bibliothèques respectant cette spécification simple – seront techniquement 100% interopérable – pourront partager un seul autoloader optimisé
• Par exemple pour utiliser Symfony 2.0 + Doctrine 2.0 + Zend Framework 2.0 dans un même projet
– Un unique autoloader pour les 3 bibliothèques – Exemple d’implémentation: http://gist.github.com/221634 – Sera certainement implémenté en C une fois le standard définitif
Les namespaces dans Symfony 2
Symfony\Components Symfony\Foundation Symfony\Framework
Symfony\Components\EventDispatcher\Event Symfony\Foundation\ClassLoader
Symfony\Components\EventDispatcher\Event
vs
sfEvent
Le nom des classes
n’est pas plus court !
Les namespaces dans Symfony 2
$classLoader = new ClassLoader('Symfony', __DIR__.'/lib'); $classLoader->register();
$container = new Builder(); $loader = new XmlFileLoader($container, __DIR__); $loader->load('services.xml');
$dumper = new PhpDumper($container); echo $dumper->dump();
Les namespaces dans Symfony 2 require __DIR__.'/lib/Symfony/Core/ClassLoader.php';
use Symfony\Foundation\ClassLoader; use Symfony\Components\DependencyInjection\Builder; use Symfony\Components\DependencyInjection\Reference; use Symfony\Components\DependencyInjection\Loader\XmlFileLoader; use Symfony\Components\DependencyInjection\Dumper\PhpDumper;
Bonne pratique
PHP 5.3 L’apport pour les entreprises
PHP 5 dans les entreprises
Depuis 2005 et l’arrivée de PHP 5.0 et surtout PHP 5.2
Adoption plus rapide dans les entreprises que dans la communauté
Rupture technologique qui a entraîné une révolution des usages
PHP 5, une rupture technologique
• Arrivée de frameworks matures : symfony, Zend Framework, CakePHP, Prado, …
• Professionnalisation des développements – Prise en compte des bonnes pratiques : tests, design patterns, sécurité, …
• Professionnalisation des développeurs – Passage d’une communauté de bidouilleurs à une communauté de
développeurs PHP professionnels – Une communauté qui se scinde en deux
L’adoption de PHP 5.3 devrait être rapide dans les entreprises
– Migration facile
– Support Windows amélioré (rapidité, intégration, fonctionnalités)
– Meilleures performances (for free)
– Apport technique limité…
– … mais les usages vont une nouvelle fois évoluer
PHP 5.3 dans les entreprises en 2010/2011
• Une évolution technologique qui va permettre de continuer le changement des usages et accélérer l’adoption massive de PHP dans les entreprises
• Ce changement devrait être une fois encore mené par les frameworks
PHP 5.3 Parlons technique…
PHP 5.3
• Beaucoup de nouveautés
– Cosmétiques : __DIR__, ?:, NOWDOC, …
– Fonctionnelles : i18n, SPL, gestion des dates, mysqlnd, …
– Structurelles : namespaces, fonctions anonymes, closures, late static binding, phar, support Windows, …
PHP 5.3 Le singleton
Le singleton nuit gravement à la santé de votre code
sfContext dans symfony est “juste” l’exception qui confirme la règle ;)
Le Singleton à travers les âges
Le Singleton en PHP 4
Pas vraiment possible à cause des limitations du language class Singleton { function &getInstance() { static $instance;
if (!$instance) { $instance = new Singleton(); }
return $instance; } }
$obj =& singleton::getInstance();
on peut toujours
instancier la classe
directement
Le Singleton en 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; }
final private function __clone() {} }
$obj = Singleton::getInstance();
ne pas oublier la
méthode __clone()
Le Singleton en 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() {} }
Le Singleton en PHP 5.3
class Foo extends Singleton {} class Bar extends Singleton {}
$a = Foo::getInstance(); $b = Bar::getInstance();
Late Static Binding
__callStatic()
User::find(1)
User::findByUsername('fabien');
Fonctions anonymes
Fonctions Anonymes
Une fonction anonyme est une fonction déclarée à la volée (sans nom)
function () { echo 'Hello world!'; };
Fonctions Anonymes
Pour être affectée à une variable
$hello = function () { echo 'Hello world!'; };
Fonctions Anonymes
Puis être utilisée
$hello();
call_user_func($hello);
Fonctions Anonymes
et/ou être passé en argument d’une fonction
function foo(Closure $func) { $func(); }
foo($hello);
Fonctions anonymes $hello = function ($name) { echo 'Hello '.$name; };
$hello('Fabien');
call_user_func($hello, 'Fabien');
function foo(Closure $func, $name) { $func($name); }
foo($hello, 'Fabien');
Que faire avec des fonctions anonymes ?
array_*
Simplification de l’usage de
array_map()
array_reduce()
array_filter()
Comment récupérer un tableau avec les titres des objets ?
class Article { public function __construct($title) { $this->title = $title; }
public function getTitle() { return $this->title; } }
$articles = array( new Article('Forum PHP 2009 - part 1'), new Article('Forum PHP 2009 - part 2'), new Article('Vivement Noël !'), );
$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
mémoire rapidité
$mapper = function ($article) { return $article->getTitle(); }; $titles = array_map($mapper, $articles);
180 100
Une closure est une fonction anonyme qui se souvient du contexte
dans laquelle elle a été crée…
$method = 'getTitle';
$mapper = function ($article) use($method) { return $article->$method(); };
$titles = array_map($mapper, $articles);
$mapper = function ($method) { return function ($article) use($method) { return $article->$method(); }; };
$titles = array_map($mapper('getTitle'), $articles);
Questions ?
Injection de Dépendance
« Dependency Injection is where components are given their dependencies through their
constructors, methods, or directly into fields. »
http://www.picocontainer.org/injection.html
class Message { public function __construct(array $options) { $this->output = new FancyOutput();
// ... }
// ... }
Impossible de changer la classe FancyOutput par une autre
class Message { public function __construct(OutputInterface $output, array $options) { $this->output = $output; $this->options = array_merge(array('with_newline' => false), $options); }
public function say($msg) { $this->output->render($msg.($this->options['with_newline'] ? "\n" : '')); } }
interface OutputInterface { public function render($msg); }
class Output implements OutputInterface { public function render($msg) { echo $msg; } }
class FancyOutput implements OutputInterface { public function render($msg) { echo sprintf("\033[33m%s\033[0m", $msg); } }
$output = new FancyOutput(); $message = new Message($output, array('with_newline' => true)); $message->say('Hello World');
Un container DI permet
de décrire les objets et leurs relations
de les configurer
de les créer
class DIContainer { 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]; } } }
// define the parameters $container->output_class = 'FancyOutput'; $container->with_newline = true;
// defined the objects $container->message = function ($c) { return new Message($c->output, array('with_newline' => $c->with_newline)); };
$container->output = function ($c) { return new $c->output_class(); };
// get the message object $container->message->say('Hello World');
spl_object_hash($container->message)
!== spl_object_hash($container->message)
$container->message = function ($c) { static $object;
if (is_null($object)) { $object = new Message($c->output, array('with_newline' => $c->with_newline)); }
return $object; };
spl_object_hash($container->message)
=== spl_object_hash($container->message)
function asShared($callable) { return function ($c) use ($callable) { static $object;
if (is_null($object)) { $object = $callable($c); } return $object; }; }
$container->message = $container->asShared(function ($c) { return new Message(
$c->output,
array('with_newline' => $c->with_newline)
); });
class DIContainer { 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]; } } }
class DIContainer { 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 pour un
container DI complet
plus d’infos…
http://fabien.potencier.org/article/17/on-php-5-3-lambda-functions-and-closures
http://components.symfony-project.org/dependency-injection/
http://github.com/fabpot/pimple
http://twittee.org/
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
Questions ?
Observateur
Un objet (sujet) maintient une liste d’observateurs et les informe automatiquement
des changements intervenus en appelant une méthode
Un dispatcher est un point central permettant de gérer les connections entre les sujets et les observateurs
// an anonymous listener $listener = function ($parameters) { echo "Hello {$parameters['name']}\n"; };
// register the listener with the dispatcher $dispatcher = new EventDispatcher(array( 'foo' => $listener, ));
// notify the event somewhere $dispatcher->notify('foo', array('name' => 'Fabien'));
class EventDispatcher { function __construct($listeners) { $this->listeners = $listeners; }
function notify($name, $parameters = array()) { $this->listeners[$name]($parameters); } }
Comment enregistrer plusieurs observateurs ?
$listener = new EventListeners( function ($parameters) { echo "Hello {$parameters['name']}?\n"; }, function ($parameters) { echo "Hello {$parameters['name']}!\n"; } );
$dispatcher = new EventDispatcher(array( 'foo' => $listener ));
$dispatcher->notify('foo', array('name' => 'Fabien'));
class EventListeners { function __construct() { $this->listeners = func_get_args(); }
function __invoke($parameters = array()) { foreach ($this->listeners as $listener) { $listener($parameters); } } }
with Matthew Weier O’Pheinney
I will reveal the first alpha release of Symfony 2.0!
symfony-live.com
with Matthew Weier O’Pheinney
… with Matthew Weier O'Phinney as a special guest
symfony-live.com
Questions?
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/