Les nouveautés de PHP 5.3

Et comment migrer de PHP 5.2 vers PHP 5.3

| John Mertic (auteur) | Guillaume Rossolini (traducteur) |

Initialement décrit comme « PHP 6 sans le support natif d'Unicode », PHP 5.3 est une amélioration riche en nouvelles fonctionnalités pour la branche de la version 5. Cette version est destinée à préparer les développeurs aux évolutions majeures de PHP, en ajoutant de nombreuses fonctionnalités, en opérant du nettoyage moyennant l'amélioration des fonctionnalités, en résolvant des problèmes liés à certaines plateformes et en décourageant l'utilisation de fonctionnalités qui n'existeront plus dans les versions ultérieures. Dans cette série « les nouveautés de PHP 5.3 », nous allons entrer dans le détail de ces fonctionnalités et voir comment elles peuvent être utilisées dans votre application Web.

Cet article est traduit de « What's new in PHP V5.3 » par John Mertic, publié initialement sur IBM Developer Works.

Commentez ♪

- Titre : Les nouveautés de PHP 5.3

- Auteurs : John Mertic (auteur), Guillaume Rossolini (traducteur)

- Parution : 20 juin 2009

- Mise à jour : 29 juin 2009

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2008 John Mertic et Guillaume Rossolini. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Modifications à l'interface objet

- I-A. PHP 5 et la programmation orientée objet

- I-A-1. Amélioration de la gestion des méthodes et des propriétés statiques

- I-A-2. La méthode magique __callStatic()

- I-A-3. Appels statiques dynamiques

- I-B. Liaison statique différée (late static binding)

- I-C. Standard PHP Library

- I-D. Ramasse-miette circulaire

- I-E. Conclusion

- II. Fermetures et fonctions lambda

- II-A. Introduction

- II-B. Fonctions lambda

- II-C. Fermetures

- II-D. Fermetures et objets

- II-E. Fermetures et réflexion

- II-F. Pourquoi les fermetures ?

- II-G. Conclusion

- III. Espaces de noms (namespaces)

- III-A. Introduction

- III-B. Les espaces de noms en PHP

- III-B-1. Définir un espace de noms

- III-B-2. Utiliser du code avec espaces de noms

- III-B-3. Résolution d'espaces de noms

- III-C. Cas d'utilisation pour les espaces de noms en PHP

- III-C-1. Code produit par des tiers

- III-C-2. Éviter les collisions de fonctions utilitaires

- III-C-3. Remplacer des noms de fonction internes de PHP

- III-D. Conclusion

- IV. Création et utilisation d'archives Phar

- IV-A. Introduction

- IV-B. Créer une archive Phar

- IV-C. Le fichier bouchon de Phar

- IV-D. Ajouter des fichiers à l'archive

- IV-E. Utiliser des archives Phar

- IV-E-1. Intégrer le code d'une archive Phar dans votre application

- IV-E-2. Exécuter une application PHP depuis une archive Phar

- IV-F. Conclusion

- V. Migration depuis PHP 5.2

- V-A. Introduction

- V-B. Changements syntaxiques

- V-C. Modifications aux fonctions et méthodes

- V-D. Modifications d'extensions

- V-E. Modifications de compilation

- V-F. Modifications .ini

- V-G. Éléments marqués pour suppression (deprecated)

- V-H. Conclusion

I - Modifications à l'interface objet

Cette section est une traduction de : http://www.ibm.com/developerworks/opensource/library/os-php-5.3new1/

I-A - PHP 5 et la programmation orientée objet

Lorsque PHP 5 fut diffusé en 2004, c'était un très grand bond en avant par rapport à ce qu'était PHP 4 et à sa conception de programmation orientée objet (POO). Elle ajoutait plusieurs améliorations nécessaires comme la visibilité dans les classes, de véritables constructeurs et destructeurs, une mesure de suggestion de types et une API d'introspection de classes. Elle ouvrait la porte à de la POO avancée en PHP, et vous permettait d'implémenter plus aisément de nombreux motifs de conception ainsi que des API et des classes mieux conçues.

Dans PHP 5.3, de nombreux ajouts ont été faits pour améliorer la POO. Ces améliorations sont faites dans le domaine de la syntaxe du langage et des performances. Pour commencer, voyons les nouvelles fonctionnalités disponibles avec les méthodes et les propriétés statiques.

I-A-1 - Amélioration de la gestion des méthodes et des propriétés statiques

Une amélioration utile de PHP 5 était la possibilité de définir une propriété ou une méthode comme étant statique (PHP 4 connaissait les propriétés et les méthodes statiques dans les classes, mais n'avait pas la possibilité de dire que la propriété ou la classe était conçue pour un accès statique). L'accès statique est particulièrement utile pour implémenter le motif de conception « Singleton », d'après lequel il n'existe qu'une seule instance de la classe.

PHP 5.3 ajoute diverses fonctionnalités pour améliorer le support des propriétés et des méthodes statiques dans une classe. Tout d'abord, nous allons voir la nouvelle méthode magique : __callStatic()

I-A-2 - La méthode magique __callStatic()

PHP 5 possède plusieurs méthodes spécifiques aux classes, connues sous le nom de méthodes magiques. Lorsqu'elles sont définies dans la classe, ces méthodes apportent des fonctionnalités spéciales et elles permettent la surcharge (la capacité de permettre à une méthode d'accepter différents types de paramètres) ainsi que le polymorphisme (la capacité de permettre à différents types d'utiliser la même interface). Elles ouvrent également la porte à l'utilisation aisée de différents types de POO et de motifs de conception avec PHP.

Dans PHP 5.3, une nouvelle méthode magique est ajoutée : __callStatic(). Elle fonctionne de manière similaire à la méthode magique __call(), qui est prévue pour gérer les appels de méthodes qui ne sont pas définies ou pas visibles dans une classe. Cependant, __callStatic() est conçue pour gérer les appels statiques, ce qui nous donne la possibilité de mieux prévoir notre surcharge de méthodes. Voici un exemple d'utilisation de cette méthode :

Listing 1. Exemple d'utilisation de __callStatic() contre __call()

class Foo
{
public static function __callStatic($name, $args)
{
echo "La méthode $name est appelée de manière statique";
}

public function __call($name, $args)
{
echo "La méthode $name est appelée";
}
}

Foo::chien();       // affiche "La méthode chien est appelée de manière statique"
$foo = new Foo;
$foo->chien();      // affiche "La méthode chien est appelée"

La déclaration de la méthode __callStatic() doit être public et static. De même, la méthode __call() doit également être définie public, comme toutes les méthodes magiques.

I-A-3 - Appels statiques dynamiques

Les variables de variables sont une fonctionnalité sympathique de PHP. Cela signifie que vous pouvez utiliser la valeur « chaîne » d'une variable pour spécifier le nom d'une autre variable. En d'autres mots, vous pourriez faire quelque chose comme :

Listing 2. Variables de variables

$x = 'y';
$$x = 'z';
echo $x;  // affiche 'y'
echo $y;  // affiche 'z'
echo $$x; // affiche 'z'

Le même concept peut être utilisé pour les fonctions, ou même pour les méthodes de classes, comme le montre cet exemple :

Listing 3. Noms variables de fonctions et de méthodes de classes

class Chien
{
public function aboyer()
{
echo "Ouah !";
}
}

$class = 'Chien' ;
$action = 'aboyer';
$x = new $class(); // instancie la classe 'Chien'
$x->$action();     // affiche "Ouah !"

Une nouveauté de PHP 5.3 est la possibilité d'avoir le nom de la classe en tant que variable lors d'un appel statique, ce qui offre quelques possibilités comme démontré ci-dessous :

Listing 4. Nom variable de classe

class Chien
{
public static function aboyer()
{
echo "Ouah !";
}
}

$class = 'Chien';
$action = 'aboyer';
$class::$action();  //affiche "Ouah !"

Cet ajout complète la fonctionnalité des variables variables de PHP en leur permettant d'être utilisées dans à peu près toutes les situations avec PHP.

Voyons maintenant une autre amélioration utile de l'utilisation de méthodes et de propriétés statiques : « late static binding ».

I-B - Liaison statique différée (late static binding)

L'une des choses les plus agaçantes avec PHP avant 5.3 est comment les propriétés et les membres statiques sont gérés. Jusqu'à présent, les références statiques, comme celles faites avec self ou __CLASS__, étaient résolues dans la même portée que celle dans laquelle la fonction était définie. Le problème est que la référence est incorrecte si la classe est étendue et si l'appel est fait depuis la nouvelle classe fille. Late static binding a été ajouté à PHP 5.3 pour résoudre ce problème. Pour mieux illustrer, créons une classe avec une méthode statique :

Listing 5. Classe Foo avec une méthode statique test()

class Foo
{
protected static $name = 'Foo';

public static function test()
{
return self::$name;
}
}

Étendons cette classe. Nous allons définir de nouveau la propriété $name dans la classe fille :

Listing 6. La classe fille Bar étend la classe parent Foo

class Bar extends Foo
{
protected static $name = 'Bar';
}

Nous faisons alors l'appel statique en listing 7

Listing 7. Appel statique à la méthode test()

echo Bar::test();

Ce qui est affiché par cet appel est la chaîne « Foo ». C'est à cause de la référence self::$name faite dans la méthode test() dans la classe Foo. La liaison a lieu de cette manière parce que c'est à cet endroit que la méthode est définie.

PHP 5.3 ajoute le mot clef static pour permettre de faire cette référence avec la classe actuelle. Ainsi, faites le changement dans la classe Foo ci-dessus pour utiliser ce mot clef en Listing 8, et nous verrons que « Bar » sera affiché à la place :

Listing 8. Using the static keyword

class Foo
{
protected static $name = 'Foo';

public static function test()
{
return static::$name;
}
}

class Bar extends Foo
{
protected static $name = 'Bar';
}

echo Bar::test(); // affiche 'Bar'

Le mot clef static ne fonctionne pas de la même manière que ce code fonctionnerait en contexte non statique. Cela signifie que les règles normales d'héritage ne fonctionnent pas pour les appels statiques. Le mot clef static va simplement essayer de résoudre l'appel dans la classe actuelle plutôt que dans la classe dans laquelle la fonction est définie. Il est important de bien le comprendre.

Maintenant que nous avons vu quelques améliorations avec les propriétés et les méthodes statiques, voyons quelques nouvelles classes ajoutées à une partie très utile de PHP 5 : la Standard PHP Library.

I-C - Standard PHP Library

La Standard PHP Library (SPL) est un ensemble d'interfaces et de classes ajoutées en PHP 5 et conçues pour résoudre des problèmes courants. Ces problèmes incluent le besoin d'un objet que l'on puisse parcourir par itérations, donner à un objet le comportement d'un tableau ou implémenter une liste liée. L'avantage d'utiliser ces classes et ces méthodes est qu'elles sont natives à PHP, ce qui signifie qu'elles sont plus rapides que si elles étaient implémentées en PHP. Dans de nombreux cas, elles permettent également d'utiliser beaucoup de fonctions internes de PHP directement sur ces objets, comme l'interface Iterator qui est compatible avec la structure foreach pour parcourir un objet.

PHP 5.3 ajoute quelques classes supplémentaires à la SPL. Nous avons parlé plus haut de la liste doublement chainée, c'est la classe SplDoublyLinkedList dans la SPL. Elle est utilisée par deux autres nouvelles classes de la SPL : SplStack, qui implémente une pile, et SplQueue, qui implémente une file.

Voyons comment utiliser la classe SplStack pour implémenter une pile :

Listing 9. Utiliser SplStack

$stack = new SplStack();

// ajouter de nouveaux éléments à la pile
$stack->push('a');
$stack->push('b');
$stack->push('c');

// voir combien d'éléments sont dans la pile
echo count($stack); // renvoie 3

// itérer sur les éléments de la pile
foreach ( $stack as $item )
echo "[$item],";
// affiche : [c],[b],[a]

// supprimer un élément du dessus de la pile
echo $stack->pop(); // renvoie 'c'

// voir combien d'éléments sont dans la pile maintenant
echo count($stack); // renvoie 2

SplQueue fonctionne de manière similaire, mais comme une file le ferait (« premier élément entré, premier élément sorti » au lieu de «dernier élément entré, premier élément sorti » comme la pile). De plus, il existe une implémentation tas (SplHeap) ainsi que certaines implémentations de files et de tas pour des situations précises (SplMinHeap, SplMaxHeap et SplPriorityQueue).

Un autre ajout est la classe SplFixedArray qui, comme le nom le suggère, est une implémentation de tableau à taille fixe. Elle est très rapide ; en fait, elle est tellement rapide qu'elle a été mesurée pour un gain de 10 à 30% par rapport à l'implémentation Array native de PHP. Ce gain de vitesse est dû au fait que le tableau est de taille fixe, contrairement au type Array natif de PHP, et que les indexes non numériques ne sont pas permis. Le Listing 10 montre son utilisation :

Listing 10. SplFixedArray

$array = new SplFixedArray(3);
$array[0] = 'chien';
$array[1] = 'chat';
$array[2] = 'oiseau';
$array->setSize(4); // augmenter la taille dynamiquement
$array[3] = 'souris';
foreach ( $array as $value )
echo "[$value],";

Affiche:
[chien],[chat],[oiseau],[souris]

De plus, quelques itérateurs ont été ajoutés : FilesystemIterator et GlobIterator. Ils fonctionnent de la même manière que les autres classes d'itérateurs de PHP, mais ils sont conçus pour certaines situations.

Un autre changement avec la SPL est qu'elle est désormais toujours activée depuis PHP 5.3. Dans les versions précédentes, vous pouviez la désactiver au moment de la compilation, mais ce n'est plus possible depuis PHP 5.3.

Les nouveautés de la SPL ajoutent des fonctionnalités utiles à PHP, faciles à utiliser, ainsi que des implémentations de structures de données comme les listes doublement liées, les piles, les files et les tas. Ces classes peuvent être utilisées pour remplacer les implémentations « utilisateur » que vous pourriez avoir, ce qui fera gagner de la rapidité à vos scripts et permettra une meilleure intégration avec diverses structures et fonctions PHP.

Maintenant que nous avons vu les ajouts à la SPL, voyons comment la POO a bénéficié d'importantes améliorations en performances et en consommation mémoire dans PHP 5.3 grâce à l'ajout du ramasse-miette (garbage collection) pour les références circulaires.

I-D - Ramasse-miette circulaire

Un problème que les développeurs PHP rencontrent du point de vue des performances est le ramassage des miettes (garbage collection). PHP a un ramasse-miette assez simple qui s'occupe d'un objet simplement lorsqu'il n'est plus visible. PHP le fait en interne à l'aide d'un compteur de références, de telle manière que lorsque le compteur atteint zéro (c'est-à-dire qu'il n'y a plus aucune référence à l'objet), l'objet est ramassé et la mémoire qui lui était attribuée est libérée.

Cela fonctionne plutôt bien, mais cela peut devenir un problème dans les situations où un objet référence un autre objet en relation parent-enfant. Dans cette situation, le compteur de références pour ces objets n'agit pas, ainsi la mémoire utilisée pour ces objets reste dans la mémoire non référencée et elle n'est jamais libérée avant la fin de la requête. Voici un exemple permettant de faire apparaître ce problème :

Listing 11. Relation de classes parent-enfant mal gérée par le ramasse-miette dans PHP 5.2 et antérieurs

class LeParent
{
public function __construct()
{
$this->child = new Enfant($this);
}
}

class Enfant
{
public function __construct(LeParent $parent)
{
$this->parent = $parent;
}
}

Dans cette situation, chaque fois que vous créez une instance de la classe Parent et que cette instance devient hors de portée, la mémoire n'est pas libérée, ainsi le script continue de consommer davantage de mémoire à mesure qu'il reste en exécution. Il y a quelques solutions possibles en tant qu'utilisateur de PHP, comme créer un destructeur pour la classe parent afin de libérer l'objet enfant. Ce destructeur doit être appelé spécifiquement avant de détruire la référence à la classe parent. Alors que cette méthode fonctionne, elle complique passablement votre code.

Dans PHP 5.3, le ramasse-miette détecte ces références circulaires et il est capable de libérer la mémoire qu'elles utilisent, de façon à ce que la consommation de mémoire par PHP reste linéaire lors de l'exécution du script. Alors que chaque référence à la classe Parent est supprimée, la référence à la classe Enfant à l'intérieur de Parent est également ramassée.

I-E - Conclusion

PHP a fait bien du chemin sur le plan du support de la programmation orientée objet, depuis le faible support ajouté en PHP 4 aux ajouts nettement améliorés dans PHP5 et aux correctifs qui ont suivi. Aujourd'hui, PHP 5.3 a reçu des améliorations intéressantes, notamment des ajouts de syntaxe comme la nouvelle méthode statique __callStatic(), les appels statiques dynamiques, late static binding, les méthodes et les propriétés statiques. Les nouveautés de la SPL avec l'implémentation des listes doublement liées, les piles, les files et les tas mettent à votre disposition des structures de données classiques et simplifient leur utilisation. Enfin, le ramasse-miette circulaire, longuement attendu, résout des problèmes de mémoire et de performances pour les classes auto référencées en implémentant un ramasse-miette nettement amélioré qui libère correctement la mémoire pour ces références circulaires. Toutes ces fonctionnalités font de PHP 5.3 un langage bien plus intéressant pour la programmation orientée objet.

II - Fermetures et fonctions lambda

Cette section est une traduction de : http://www.ibm.com/developerworks/opensource/library/os-php-5.3new2/

II-A - Introduction

Dans cette deuxième partie, nous abordons les fermetures et les fonctions lambda. Elles sont conçues pour rendre la programmation plus facile en vous permettant de définir des fonctions jetables qui peuvent être utilisées dans de multiples contextes.

Les concepts de fermetures et de fonctions lambda ne sont pas nouveaux ; ils viennent tous deux du monde de la programmation fonctionnelle. La programmation fonctionnelle est un style de programmation qui déplace le centre d'intérêt depuis l'exécution de commandes à l'évaluation d'expressions. Ces expressions sont formées en utilisant des fonctions, qui sont assemblées pour trouver le résultat qui pourrait nous convenir. Ce style de programmation était plus fréquemment utilisé dans un cadre académique, mais il est également constaté dans les domaines de l'intelligence artificielle et des mathématiques, et il peut être présent dans des applications commerciales avec des langages comme Erlang, Haskell et Scheme.

Les fermetures furent développées initialement dans les années 1960 comme une partie de Scheme, l'un des plus connus des langages de programmation fonctionnelle. Les fonctions lambda et les fermetures sont souvent présentes dans les langages qui permettent aux fonctions d'être traitées comme de véritables valeurs, c'est-à-dire que les fonctions peuvent être créées à la volée et passées en tant que paramètres à d'autres structures.

Depuis lors, les fermetures et les fonctions lambda ont percé hors du monde de la programmation fonctionnelle vers des langages comme JavaScript, Python et Ruby. JavaScript est l'un des langages les plus populaires supportant les fermetures et les fonctions lambda. En fait, il les utilise comme un moyen de proposer la programmation orientée objet, où les fonctions sont imbriquées dans d'autres fonctions pour jouer le rôle de membres privés. Le Listing 1 montre un exemple d'utilisation de fermetures en JavaScript :

Listing 1. Un objet JavaScript construit avec une fermeture

var Exemple = function()
{
this.public = function()
{
return "Ceci est une méthode publique";
};

var private = function()
{
return "Ceci est une méthode privée";
};
};

Example.public()  // renvoie "Ceci est une méthode publique"
Example.private() // erreur – ne fonctionne pas

Comme nous le voyons dans Listing 1, les fonctions membres de l'objet Exemple sont définies comme fermetures. Dans la mesure où la méthode privée a une portée de variable locale (contrairement à la méthode publique attachée à l'objet Exemple avec le mot clef this), elle n'est pas visible du monde extérieur.

Maintenant que nous avons une mesure de connaissances historiques sur l'origine de ces concepts, voyons les fonctions lambda en PHP. Le concept de fonctions lambda est la base des fermetures et il donne une bien meilleure méthode de création à la volée de fonction, par rapport à la fonction déjà existante dans PHP : create_function().

[NDT Certaines fonctionnalités décrites ici ont été supprimées depuis la rédaction initiale de ce document. En effet, avec le cycle bêta de PHP 5.3, des incompatibilités importantes ont été décelées. Le wiki de PHP décrit cela. Nos lecteurs ont décrit ici une manière alternative : Commentez ]

II-B - Fonctions lambda

Les fonctions lambda (ou « fonctions anonymes » comme on les appelle souvent) sont simplement des fonctions jetables qui peuvent être définies à tout moment et qui sont habituellement liées à une variable. Les fonctions elles-mêmes existent uniquement dans la portée de la variable dans laquelle elles sont définies ; ainsi, lorsque cette variable devient hors de portée, la fonction disparaît également. L'idée des fonctions lambda vient d'un travail mathématique des années 1930. Connu comme « lambda calculus », il avait pour objectif d'analyser la définition et l'application des fonctions, ainsi que le concept de récursion. Le travail de lambda calculus fut utilisé pour développer des langages de programmation fonctionnelle, par exemple Lisp et Scheme.

Les fonctions lambda sont pratiques dans un certain nombre de situations, en particulier pour les fonctions PHP qui nécessitent une fonction de rappel. L'une de ces fonctions est array_map(), qui nous permet de parcourir un tableau et d'appliquer une fonction de rappel à chacun de ses éléments. Dans les versions précédentes de PHP, le plus gros problème était qu'il n'y avait pas de moyen propre de créer la fonction de rappel ; nous étions contraints à utiliser l'une de ces approches au problème :

1. Nous pouvons définir la fonction de rappel ailleurs dans le code de manière à savoir qu'elle est disponible. C'est déroutant, car cela déplace ailleurs une partie de l'implémentation de l'appel, ce qui est peu pratique pour la lisibilité et pour la maintenance, surtout si nous n'utilisons cette fonction à aucun autre moment ;

2. Nous pouvons définir la fonction de rappel dans le même bloc de code, mais avec un nom. Tandis que cela aide à la cohésion du code, nous devons ajouter un bloc conditionnel autour de la définition afin d'éviter les collisions d'espace de noms. Listing 2 est un exemple de cette approche ;

3. Nous pouvons utiliser create_function(), qui fait partie de PHP depuis sa version 4, pour créer la fonction à l'exécution. Tandis que d'un point de vue fonctionnel, cela donne l'effet désiré, il y a quelques inconvénients. L'un des problèmes majeurs est que la compilation a lieu ors de l'exécution au lieu de lors de la compilation, ce qui empêche les caches d'opcodes de mettre la fonction en cache. C'est également une syntaxe assez laide et la coloration de code de la plupart des EDI ne fonctionne pas.

Listing 2. Définir une fonction de rappel nommée dans le même bloc de code

function quoteWords()
{
if (!function_exists ('quoteWordsHelper')) {
function quoteWordsHelper($string) {
return preg_replace('/(\w)/','"$1"',$string);
}
}
return array_map('quoteWordsHelper', $text);
}

Tandis que les fonctions acceptant des fonctions de rappel sont puissantes, il n'y a aucun moyen de créer une fonction de rappel d'une seule traite sans du code très inélégant. Avec PHP 5.3, nous pouvons utiliser les fonctions lambda pour refaire l'exemple ci-dessus d'une manière bien plus propre :

Listing 3. quoteWords() utilisant une fonction lambda pour le rappel

function quoteWords()
{
return array_map('quoteWordsHelper',
function ($string) {
return preg_replace('/(\w)/','"$1"',$string);
});
}

Nous voyons une syntaxe bien plus propre pour définir ces fonctions, qui peuvent être optimisées pour les performances par les caches d'opcodes. Nous avons également amélioré la lisibilité et la compatibilité avec la coloration syntaxique. Maintenant, partons de là pour rebondir sur le concept des fermetures en PHP.

II-C - Fermetures

Les fonctions lambda par elles-mêmes ajoutent peu de choses par rapport à ce que nous pouvions faire jusque-là. Comme nous l'avons vu, il était possible de faire la même chose avec create_function(), bien qu'avec une syntaxe plus laide et des performances moins qu'idéales. Cependant, ce sont également des fonctions jetables et elles ne maintiennent aucune sorte d'état, ce qui limite leur utilité. Voici où les fermetures entrent en scène et poussent les fonctions lambda au niveau supérieur.

Une fermeture est une fonction évaluée dans son propre environnement, qui a une ou plusieurs variables liées, disponibles au moment où la fonction est appelée. Les fermetures viennent du monde de la programmation fonctionnelle, où les développeurs jonglent avec un certain nombre de concepts. Les fermetures sont comme des fonctions lambda, mais elles sont plus intelligentes dans la mesure où elles ont la capacité d'interagir avec des variables hors de l'environnement dans lequel la fermeture est définie.

Voyons comment définir une fermeture en PHP. Le listing 4 montre un exemple de fermeture qui importe une variable de l'environnement externe et qui l'affiche simplement à l'écran :

Listing 4. Exemple de fermeture simple

$chaine = "Hello World!";
$fermeture = function() use ($chaine) { echo $chaine; };

$fermeture();

Affiche :
Hello World!

Les variables importées de l'environnement externe sont spécifiées dans la clause use de la définition de la fermeture. Par défaut, elles sont transmises par valeur, ce qui signifie que modifier la valeur passée dans la définition de la fermeture ne modifie pas la valeur externe. Nous pouvons cependant le faire en préfixant la variable par l'opérateur &, qui est utilisé dans les définitions de fonctions pour indiquer le passage par référence. Le listing 5 montre un exemple de cela :

Listing 5. Fermeture passant une variable par référence

$x = 1;
$closure = function() use (&$x) { ++$x; };

echo $x . "\n";
$closure();
echo $x . "\n";
$closure();
echo $x . "\n";

Affiche :
1
2
3

Nous voyons ici une fermeture utilisant une variable externe $x et l'incrémentant chaque fois qu'elle est appelée. Nous pouvons aisément mélanger les variables passées par valeur et par référence dans la clause use, et elles seront gérées sans problème. Nous pouvons également avoir des fonctions qui renvoient directement une fermeture, comme le montre le Listing 6. Dans ce cas, la durée de vie de la fermeture sera plus longue que celle de la méthode qui l'a définie :

Listing 6. Fermeture retournée par une fonction

function getAppender($baseString)
{
return function($appendString) use ($baseString) {
return $baseString . $appendString;
};
}

II-D - Fermetures et objets

Les fermetures peuvent être un outil très pratique, non seulement pour la programmation fonctionnelle, mais aussi pour la programmation orientée objet. Dans cette situation, utiliser les fermetures a le même objectif qu'à l'extérieur d'une classe : contenir une fonction spécifique liée à une petite portée. Par ailleurs, elles sont tout aussi simples à utiliser dans nos objets qu'à l'extérieur.

Lorsqu'elles sont définies dans un objet, un aspect intéressant est que la fermeture peut utiliser la totalité de l'objet à travers la variable $this sans nécessiter un import explicite. Le Listing 7 le montre :

Listing 7. Fermeture dans un objet

class Chien
{
public $_nom;
public $_couleur;

public function __construct($nom, $couleur)
{
$this->_nom = $nom;
$this->_couleur = $couleur;
}

public function saluer($salut)
{
$self = $this;
return function() use ($salut, $self) {
echo "$salut, je suis un chien {$self->_couleur}"
." appelé {$self->_nom}.";
};
}
}

$chien = new Chien("Rover","rouge");
$fermeture = $chien->saluer("Bonjour");
$fermeture();

Affiche :
Bonjour, je suis un chien rouge appelé Rover.

Ici, nous utilisons de manière explicite depuis la fermeture le salut donné à la méthode saluer() qui définit la fermeture. Dans la fermeture, nous récupérons également la couleur et le nom du chien transmis au constructeur et enregistrés dans l'objet.

Les fermetures définies dans une classe sont fondamentalement les mêmes que celles définies à l'extérieur d'un objet. La seule différence est l'importation automatique de l'objet par la variable $this. Nous pouvons désactiver ce comportement en définissant la fermeture comme static.

Listing 8. Fermeture statique

class Maison
{
public function peindre($couleur)
{
return static function() use ($couleur) {
echo "Peindre la maison en $couleur...";
};
}
}

$maison = new Maison();
$maison->peindre('rouge');

Affiche :
Peindre la maison en rouge...

Cet exemple est similaire à la classe Chien définie dans le Listing 5. La grande différence est que l'on n'utilise aucune propriété de l'objet depuis la fermeture puisqu'elle est définie static.

Le grand avantage d'utiliser une fermeture statique par rapport à une fermeture non statique à l'intérieur d'un objet, est pour les économies de mémoire. Puisqu'il n'est pas nécessaire d'importer l'objet dans la fermeture, nous pouvons économiser une jolie quantité de mémoire, surtout si nous avons de nombreuses fermetures qui n'ont pas besoin de cette fonctionnalité.

[NDT Les fermetures static ont été désactivées depuis l'écriture de cet article : http://wiki.php.net/rfc/closures/removal-of-this]

Un autre aspect intéressant pour les objets est l'ajout d'une méthode magique __invoke(), qui permet à l'objet lui-même d'être appelé comme une fermeture. Si cette méthode est définie, elle est utilisée lorsque l'objet est appelé dans ce contexte. Le Listing 9 le montre :

Listing 9. Utiliser la méthode __invoke()

class Chien
{
public function __invoke()
{
echo "Je suis un chien !";
}
}

$chien = new Chien();
$chien();

Appeler la référence d'objet montrée en Listing 9 comme une fonction appelle automatiquement la méthode magique __invoke(), provoquant un comportement de fermeture par la classe elle-même.

Les fermetures peuvent s'intégrer dans du code orienté objet aussi bien que dans du code procédural. Voyons maintenant les interactions avec la puissante API de réflexion de PHP.

II-E - Fermetures et réflexion

[NDT Les méthodes getClosure() et getClosureThis() ont été désactivées depuis l'écriture de cet article : http://wiki.php.net/rfc/closures/removal-of-this]

PHP dispose d'une fonctionnalité bien utile de réflexion qui nous permet de rétro concevoir des classes, des interfaces, des fonctions et des méthodes. De conception, les fermetures sont des fonctions anonymes, ce qui signifie qu'elles n'apparaissent pas dans l'API de réflexion.

Cependant, une nouvelle méthode getClosure() a été ajoutée aux classes ReflectionMethod et ReflectionFunction afin de permettre à PHP de créer dynamiquement une fermeture à partir de la fonction ou de la méthode spécifiée. Elle agit comme une macro dans ce contexte, où appeler une méthode ou une fonction par l'intermédiaire de la fermeture génère l'appel de fonction dans le contexte dans lequel elle est définie. Le Listing 10 montre comment cela fonctionne :

Listing 10. Utiliser la méthode getClosure()

class Compteur
{
private $x;

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

public function incrémente()
{
$this->x++;
}

public function valeurActuelle()
{
echo $this->x . "\n";
}
}
$classe = new ReflectionClass('Compteur');
$méthode = $classe->getMethod('valeurActuelle');
$fermeture = $méthode->getClosure();
$fermeture();
$classe->incrémente();
$fermeture();

Affiche :
0
1

Un effet de bord intéressant de cette approche est que cela nous permet d'avoir accès à des membres privés et protégés d'une classe par l'intermédiaire de la fermeture, ce qui peut s'avérer pratique pour les tests unitaires des classes. Le Listing 11 est un exemple d'accès à une méthode privée dans une classe.

Listing 11. Utiliser une méthode privée d'une classe

class Exemple
{
....
private static function secret()
{
echo "Je suis une méthode qui se cache !";
}
...
}

$classe = new ReflectionClass('Exemple');
$méthode = $class->getMethod('secret');
$fermeture = $méthode->getClosure();
$fermeture();

Affiche :
Je suis une méthode qui se cache !

De plus, nous pouvons utiliser l'API de réflexion pour inspecter une fermeture elle-même, comme le montre le Listing 12. Nous transmettons simplement la référence à la variable à la fermeture dans le constructeur de la classe ReflectionMethod.

Listing 12. Inspection d'une fermeture en utilisant l'API de réflexion

$fermeture = function ($x, $y = 1) {};
$m = new ReflectionMethod($fermeture);
Reflection::export ($m);

Affiche :
Method [ <internal> public method __invoke ] {
- Parameters [2] {
Parameter #0 [ <required> $x ]
Parameter #1 [ <optional> $y ]
}
}

En termes de compatibilité avec le code existant, le nom de classe Closure est désormais réservé par le moteur PHP pour enregistrer les fermetures. Ainsi, toute classe utilisant ce nom devra être renommée.

L'API de réflexion a un excellent support des fermetures, comme nous l'avons vu, dans la mesure où elle est capable de créer dynamiquement des fonctions et des méthodes. Elle peut également inspecter une fermeture comme le peut n'importe quelle fonction.

II-F - Pourquoi les fermetures ?

Comme nous l'avons vu dans les exemples pour les fonctions lambda, l'une des utilisations les plus évidentes des fermetures est dans les quelques fonctions PHP qui acceptent une fonction de rappel en paramètre. En revanche, les fermetures peuvent être utiles dans tout contexte où nous avons besoin d'encapsuler de la logique dans sa propre portée. Un exemple de cela est la réorganisation de code pour aider à sa simplification et à le rendre davantage lisible. Prenons l'exemple suivant qui montre un enregistreur utilisé pendant l'exécution de requêtes SQL :

Listing 13. Code archivant des requêtes SQL

$db = mysqli_connect("serveur","utilisateur","mot de passe");
Enregistreur::archive('debug','database','Connecté à la base de données');

$db->query("insert into parts (part, description)
values ('Marteau','Martèle les ongles')");
Enregistreur::archive('debug','database','Insérer Marteau dans la table parts');

$db->query("insert into parts (part, description)
values ('Vrille','Fait des trous dans du bois')");
Enregistreur::archive('debug','database','Insérer Vrille dans la table parts');

$db->query("insert into parts (part, description)
values ('Scie','Coupe du bois')");
Enregistreur::archive('debug','database','Insérer Scie dans la table parts');

Une chose qui se démarque dans le Listing 13 est le nombre de fois que l'on répète les mêmes opérations. Chaque appel à Enregistreur::archiver() a les deux mêmes premiers arguments. Afin d'y remédier, nous pouvons déplacer cet appel de méthode dans une fermeture et faire les appels à cette fermeture. Le code résultant est montré ci-dessous :

Listing 14. Code remanié d'archivage de requêtes SQL

$logdb = function ($string) {
Enregistreur::archive('debug','database',$string);
};

$db = mysqli_connect("serveur","utilisateur","mot de passe");
$logdb('Connecté à la base de données');

$db->query("insert into parts (part, description)
values ('Marteau','Martèle les ongles')");
$logdb('Insérer Marteau dans la table parts');

$db->query("insert into parts (part, description)
values ('Vrille','Fait des trous dans le bois')");
$logdb('Insérer Vrille dans la table parts');

$db->query("insert into parts (part, description)
values ('Scie','Coupe le bois')");
$logdb('Insérer Scie dans la table parts');

En plus d'avoir donné une apparence plus propre au code, nous avons simplifié le niveau d'archivage des requêtes SQL, car nous n'avons plus à effectuer la modification que dans un endroit.

II-G - Conclusion

Cet article montre l'utilité des fermetures comme une structure de programmation fonctionnelle dans du code PHP 5.3. Nous avons parlé des fonctions lambda et des avantages qu'ont les fermetures à leur encontre. Les objets et les fermetures s'entendent à merveille, tel que nous l'avons vu dans la gestion particulière des fermetures dans du code orienté objet. Nous avons vu que l'API de réflexion est très utile pour créer des fermetures dynamiques ainsi que pour inspecter des fermetures.

III - Espaces de noms (namespaces)

Cette section est une traduction de : http://www.ibm.com/developerworks/opensource/library/os-php-5.3new3/

III-A - Introduction

Dans cette troisième partie, nous parlerons des espaces de noms (namespaces), qui sont la fonctionnalité la plus attendue et la plus débattue de cette version de PHP. Le concept d'espace de noms donne les moyens d'aider à la prévention de problèmes avec plusieurs fonctions, classes et constantes ayant le même nom et définies plusieurs fois.

Les espaces de noms existent dans de nombreux langages incluant le C++ et le langage de programmation Java™. Ils sont apparus pour aider à l'organisation de grandes bases de code où, parfois, il y a des inquiétudes au sujet des noms de fonctions et de classes dans une application. L'utilisation d'espaces de noms peut aider à l'identification de l'objectif ou de l'utilité du code, ou encore préciser son origine. Un exemple de cela est l'espace de noms System en C# qui contient toutes les fonctions et les classes proposées par le framework .NET. Dans d'autres langages sans espaces de noms formels (comme PHP 5.2 et antérieurs), les gens émulent fréquemment les espaces de noms en essayant d'utiliser des conventions de nommage précises dans les noms de fonctions et de classes. Zend Framework le fait, c'est-à-dire que chaque nom de classe commence par Zend, et chaque espace de noms enfant est séparé par un signe de soulignement. Par exemple, la définition de la classe Zend_Db_Table est une classe qui fait partie de Zend Framework et qui a des fonctionnalités de bases de données. Un problème avec cette approche est que le code résultant peut devenir très verbeux, particulièrement si la classe ou la fonction est plusieurs à niveaux de profondeur (Zend_Cache_Backend_Apc est un exemple de cela dans Zend Framework). Un autre problème est que tout le code doit se conformer à ce style, ce qui peut être difficile si vous intégrez du code produit par d'autres personnes dans une application qui n'est pas conforme à cette convention de codage.

L'histoire des espaces de noms en PHP est une route très sinueuse. À l'origine, ils devaient faire part de PHP 5 mais ils furent enlevés des étapes de développement, car aucune implémentation correcte n'avait été trouvée. Ils revinrent ensuite à la vie dans PHP 6, puis déplacés dans PHP 5.3 après que la décision en 2007 de déplacer toutes les améliorations exceptées Unicode, vers une autre version de PHP 5.x. Tandis qu'une grande partie du comportement des espaces de noms est resté le même depuis la conception initiale, le débat du séparateur à utiliser a été très actif, avec des points de vue très différents de la part de tous les membres de la communauté concernant la solution idéale. Une décision finale d'utiliser la barre oblique arrière fut prise en octobre 2008, résolvant tous les problèmes posés par les autres opérateurs en termes de conception du langage et d'utilisabilité.

III-B - Les espaces de noms en PHP

PHP emprunte une grande partie de la syntaxe et de la conception des espaces de noms d'autres langages, et plus particulièrement de C++. Cependant, PHP réagit de manière unique à certaines situations, ce qui peut être déroutant pour les utilisateurs qui s'attendent à les voir fonctionner exactement de la même manière que dans d'autres langages. Dans cette section, nous voyons comment les espaces de noms fonctionnent en PHP.

III-B-1 - Définir un espace de noms

Définir un espace de noms est une démarche triviale. Ajoutez simplement la ligne suivante du Listing 1 en tant que première commande d'un script :

Listing 1. Définir un espace de noms

<?php
namespace Foo;
class Exemple {}
?>

La déclaration ci-dessus de namespace doit être la première commande ou sortie d'un fichier. Avoir quoi que ce soit d'autre avant cela résulte en une erreur fatale. Listing 2 montre quelques exemples de cela :

Listing 2. Mauvaises manières de définir un espace de noms

/* Fichier1.php */
<?php
echo "hello world!";
namespace Mauvais;
class Incorrecte {}
?>

/* Fichier2.php */
<?php
namespace Mauvais;
class Incorrecte {}
?>

Dans la première partie de Listing 2, nous essayons d'afficher dans la console avant la définition de l'espace de noms, ce qui a pour résultat une erreur fatale. Dans la seconde partie de l'exemple, nous avons ajouté un espace supplémentaire avant la balise d'ouverture <?php, ce qui a pour conséquence une autre erreur fatale. Il est important de faire attention à cela lorsque nous écrivons notre code, dans la mesure où c'est une erreur classique en travaillant avec les espaces de noms en PHP.

Toutefois, les deux exemples ci-dessus peuvent être réécrits en séparant la définition de l'espace de noms et le code prévu pour en faire partie vers un script indépendant qui puisse être inclus dans les scripts d'origine. Le Listing 3 montre un exemple :

Listing 3. Résoudre les mauvaises manières de définir un espace de noms

/* correct.php */
<?php
namespace Correct;
class EstCorrecte {}
?>

/* Fichier1.php */
<?php
echo "hello world!";
include './correct.php';
?>

/* Fichier2.php */
<?php
include './correct.php';
?>

NDLT : Malgré les apparences, l'erreur fatale dont il est question ici n'a rien à voir avec l'erreur classique « headers already sent » causée par la tentative d'envoi d'en têtes HTTP après le début de texte au navigateur Web. Les exemples ci-dessus démontrent que, dans le cas des espaces de noms, il s'agit d'une restriction imposée par la syntaxe du langage PHP tandis que, dans l'autre situation, il s'agit du fonctionnement du serveur Web (il est donc possible de contourner ce problème). Alors qu'il est techniquement possible d'utiliser echo dans un script PHP avant d'appeler la fonction header() dans le même script (à condition d'avoir initié la gestion différée du cache de sortie), une déclaration d'espace de noms en PHP doit se trouver tout en haut du fichier.

Maintenant que nous avons vu comment définir un espace de noms pour le nom dans un fichier, voyons comment utiliser ce code organisé dans une application.

III-B-2 - Utiliser du code avec espaces de noms

Une fois que nous avons défini un espace de noms et qu'il contient du code, nous pouvons l'appeler très simplement depuis une application. Il y a différentes options pour appeler des classes, des fonctions et des constantes organisées en espaces de noms. Une manière est de référencer l'espace de noms de manière explicite avec un préfixe au moment de l'appel. Une autre option est de définir un alias pour l'espace de noms et d'utiliser cela comme préfixe devant les appels, ce qui est conçu pour raccourcir les préfixes d'espaces de noms. Enfin, nous pouvons simplement utiliser l'espace de noms dans notre code, ce qui en fait l'espace de noms par défaut et, par défaut, fait que tous les appels utilisent cet espace de noms. Le Listing 4 illustre les différences entre les appels.

Listing 4. Appeler une fonction dans un espace de noms

/* Foo.php */
<?php
namespace Foo;
function bar()
{
echo "appel de bar...";
}
?>

/* Fichier1.php */
<?php
include './Foo.php';
Foo\bar(); // affiche "appel de bar...";
?>

/* Fichier2.php */
<?php
include './Foo.php';
use Foo as ns;
ns\bar(); // affiche "appel de bar...";
?>

/* Fichier3.php */
<?php
include './Foo.php';
use Foo;
bar(); // erreur;
?>

Le Listing 4 montre les différentes manières d'appeler une fonction bar() dans un espace de noms Foo. Dans Fichier1.php, nous voyons comment faire un appel explicite en ajoutant le nom complet de l'espace de noms avant l'appel. Dans Fichier2.php, nous utilisons un alias de l'espace de noms, ainsi nous remplaçons le nom de l'espace de noms par son alias au moment de l'appel. Enfin, Fichier3.php utilise simplement l'espace de noms, ce qui nous permet d'effectuer l'appel à bar() sans aucun préfixe.

Nous pouvons également définir plus d'un espace de noms dans un fichier en ajoutant d'autres appels à namespace dans le fichier. Le Listing 5 illustre cela :

Listing 5. Plusieurs espaces de noms dans un fichier

<?php
namespace Foo;
class Test {}

namespace Bar;
class Test {}

$a = new \Foo\Test;
$b = new \Bar\Test;

Affiche :
object(Foo\Test)#1 (0) {
}
object(Bar\Test)#2 (0) {
}

Maintenant que nous avons les connaissances de base sur la manière de faire un appel dans un espace de noms, voyons davantage de situations complexes d'espaces de noms et comment ces appels fonctionnent.

III-B-3 - Résolution d'espaces de noms

L'un des défis lors de la prise en main des espaces de noms est d'apprendre le fonctionnement de la portée. Tandis que des cas simples comme dans le Listing 4 sont faciles à comprendre, le problème survient quand nous commençons à imbriquer les espaces de noms les uns dans les autres, ou encore quand nous sommes dans un espace de noms et que nous essayons d'appeler quelque chose de l'espace global. PHP 5.3 a des règles pour résoudre automatiquement ces situations de manière judicieuse.

Créons quelques fichiers à inclure, chacun comportant la fonction bonjour() :

Listing 6. Fonction bonjour() définie dans plusieurs espaces de noms

/* global.php */
<?php
function bonjour()
{
echo "bonjour depuis l'espace global !";
}
?>

/* Foo.php */
<?php
namespace Foo;
function bonjour()
{
echo "bonjour depuis l'espace Foo !";
}
?>

/* Foo_Bar.php */
<?php
namespace Foo\Bar;
function bonjour()
{
echo "bonjour depuis l'espace Foo\Bar !";
}
?>

Le Listing 6 définit trois fois la fonction bonjour(), chacune dans un espace de noms différent : dans la portée globale, dans l'espace de noms Foo et dans l'espace de noms Foo\Bar. L'espace de noms appelant la fonction bonjour() détermine quelle fonction bonjour() est appelée. Un exemple de comment ces appels se matérialisent est montré ci-dessous. Ici, nous utilisons l'espace de noms Foo pour appeler la fonction bonjour() dans les autres espaces de noms.

Listing 7. Appel des fonctions bonjour() depuis l'espace de noms Foo

<?php
include './global.php';
include './Foo.php';
include './Foo_Bar.php';

use Foo\Bar; // identique à "use Foo\Bar as Bar"

bonjour();       // affiche 'bonjour depuis l'espace global !'
\bonjour();       // affiche 'bonjour depuis l'espace global !'
Foo\bonjour();         // affiche 'bonjour depuis l'espace Foo !'
\Foo\bonjour();         // affiche 'bonjour depuis l'espace Foo !'
Bar\bonjour();   // affiche 'bonjour depuis l'espace Foo\Bar !'
\Bar\bonjour();   // erreur
?>

Nous voyons qu'il est possible de réduire le préfixe de l'espace de noms lors d'un appel à un espace de noms enfant depuis l'espace courant (l'appel à la fonction Foo\Bar\bonjour() peut être simplifié en Bar\bonjour()). De plus, nous voyons comment préciser que nous voulons utiliser la fonction de l'espace global en ajoutant l'opérateur de résolution d'espaces de noms devant l'appel.

Maintenant que nous avons les principes du fonctionnement des espaces de noms, voyons comment les utiliser dans notre code.

III-C - Cas d'utilisation pour les espaces de noms en PHP

L'objectif principal des espaces de noms est de nous aider à mieux organiser notre code en éliminant la quantité de définitions qui vivent dans l'espace global. Dans cette section, nous verrons quelques exemples de situations dans lesquelles la présence d'espaces de noms peut aider avec peu d'efforts.

III-C-1 - Code produit par des tiers

De nombreuses applications PHP utilisent du code de plusieurs sources. C'est soit du code à la conception homogène comme ce qui existe dans le répertoire PEAR, soit du code de divers frameworks comme CakePHP ou Zend Framework, soit du code trouvé à divers endroits sur Internet. L'un des plus gros problèmes en intégrant ce code est qu'il peut ne pas être capable de cohabiter avec le reste du code ; des noms de fonctions ou de classes peuvent entrer en collision avec ce que nous avons déjà dans notre application.

Un exemple de cela est le paquetage Date dans PEAR. Il utilise le nom de classe Date, qui est un nom très générique et qui pourrait très bien exister dans d'autres endroits de notre code. Ainsi, un bon moyen de détourner cela est d'ajouter une simple commande d'espace de noms au début du fichier Date.php dans le paquetage. Nous pouvons maintenant être précis lorsque nous souhaitons utiliser la classe PEAR ou la nôtre.

Listing 8. Utiliser la classe Date de PEAR définie dans un espace de noms

<?php

require_once('PEAR/Date.php');

use PEAR\Date;    // le nom de l'espace spécifié dans PEAR/Date.php

// puisque l'espace courant est PEAR\Date,
//nous n'avons pas besoin d'ajouter le préfixe de l'espace de noms
$maintenant = new Date();
echo $maintenant->getDate();  // affiche la date au format ISO

// cet exemple montre l'espace de noms complet défini comme partie du nom de classe
$maintenant = new PEAR\Date\Date();
echo $maintenant->getDate();  // affiche la date au format ISO
?>

Nous avons défini la classe Date PEAR dans un espace de noms PEAR\Date dans le script PEAR/Date.php, ainsi, tout ce que nous avons à faire est d'inclure ce script dans notre fichier et d'utiliser le nouvel espace de noms, ou bien d'ajouter le nom de l'espace devant les noms des classes et des fonctions. Avec cela, nous pouvons inclure en toute sérénité du code tiers dans notre application.

Les collisions ne sont pas un problème uniquement avec le code produit par des tierces personnes. Elles peuvent également se produire avec des bases de code ayant des parts qui n'ont jamais été conçues pour s'approcher l'une de l'autre. Dans la section suivante, nous voyons comment les espaces de noms permettent de simplifier cette situation.

III-C-2 - Éviter les collisions de fonctions utilitaires

La très grande majorité des applications PHP ont des fonctions utilitaires. Elles ne font pas vraiment partie d'un objet de l'application et elles n'ont pas vraiment de place dans un endroit unique de l'application ; elles jouent pourtant un rôle dans l'application dans son ensemble. Toutefois, elles peuvent nous causer des problèmes de maintenance à mesure que notre application grandit.

Un endroit où cela peut être un problème est avec les tests unitaires, où nous écrivons du code qui vérifie le code qui constitue l'application. La plupart des suites de tests unitaires sont prévues pour exécuter tous les tests dans la suite complète. Par exemple, nous pourrions avoir deux fichiers utilitaires qui ne seraient jamais inclus ensemble, mais ils le sont dans la suite de tests puisque nous sommes en train de vérifier toute l'application en une fois. Tandis que concevoir une application de cette manière n'est jamais une bonne idée pour la maintenance à long terme, la situation existe fréquemment dans les larges bases de code construites avec le temps.

Le Listing 9 montre comment éviter cela. Nous avons deux fichiers, utils_gauche.php et utils_droite.php, qui sont des ensembles de fonctions utilitaires pour utilisateurs gauchers et droitiers. Nous définissons chaque fichier dans son propre espace de noms.

Listing 9. utils_gauche.php et utils_droite.php

/* utils_gauche.php */
<?php
namespace Utils\Gauche;

function quelleMain()
{
echo "J'utilise ma main gauche !";
}
?>

/* utils_droite.php */
<?php
namespace Utils\Droite;

function quelleMain()
{
echo "J'utilise ma main droite !";
}
?>

Nous définissons une fonction quelleMain() qui affiche quelle main nous utilisons. Dans le Listing 10, nous voyons comme il est facile d'inclure sans problème les deux fichiers et de naviguer entre les espaces de noms que nous souhaitons appeler.

Listing 10. Exemple d'utilisation conjointe d'utils_gauche.php et utils_droite.php

<?php
namespace {
include('./utils_gauche.php');
include('./utils_droite.php');

Utils\Gauche\quelleMain(); // affiche "J'utilise ma main gauche !"
Utils\Droite\quelleMain(); // affiche "J'utilise ma main droite !"
}

namespace {
use Utils\Gauche as u;
u\quelleMain(); // affiche "J'utilise ma main gauche !"
}

namespace {
use Utils\Droite as u;
u\quelleMain(); // affiche "J'utilise ma main droite !"
}

Maintenant, les deux fichiers peuvent être inclus à la fois sans problème, et nous précisons quel espace de noms utiliser pour prendre en charge l'appel de fonction. De plus, l'impact pour notre code existant est minime puisque la refonte de code nécessaire pour y parvenir nécessite seulement l'ajout de l'instruction use au départ du fichier pour indiquer l'espace de noms à utiliser.

La même idée peut être étendue au-delà de notre code PHP défini. Dans la prochaine section, nous voyons comment nous pouvons même remplacer des fonctions internes à l'aide des espaces de noms.

III-C-3 - Remplacer des noms de fonction internes de PHP

Bien que les fonctions internes de PHP soient souvent d'une grande aide, parfois elles ne font pas exactement ce que nous voudrions. Nous pourrions avoir besoin d'améliorer leur comportement pour se conformer au comportement que nous attendons de la fonction, mais nous voulons également définir à nouveau la fonction avec un nouveau nom afin d'éviter de segmenter davantage la portée.

Les fonctions du système de fichiers sont un cas d'utilisation candidat pour cela. Admettons que tout fichier créé par file_put_contents() ait certains droits d'accès. Par exemple, les fichiers pourraient être créés en lecture seule ; nous pouvons définir la fonction dans un espace de noms, comme indiqué ci-dessous.

Listing 11. Définir file_put_contents() dans un espace de noms

<?php
namespace Foo;

function file_put_contents( $ficher, $données, $drapeaux = 0, $contexte = null )
{
$retour = \file_put_contents( $fichier, $données, $drapeaux, $contexte );

chmod($fichier, 0444);

return $retour;
}
?>

Nous appelons la fonction interne file_put_contents() dans la fonction et nous ajoutons une barre oblique arrière avant le nom de la fonction pour préciser qu'elle doit être appelée dans la portée globale, ce qui signifie que la fonction interne est appelée. Après l'appel de la fonction interne, nous appelons chmod() sur le fichier afin d'y attribuer les permissions adéquates.

Ce ne sont que quelques exemples de comment nous pourrions utiliser les espaces de noms pour améliorer notre code. Dans chaque situation, nous évitons de faire des détournements hideux comme ajouter un préfixe au nom de classe ou de fonction pour le rendre unique. Nous savons également comment l'utilisation des espaces de noms permet d'inclure du code écrit par une tierce personne dans de grandes applications sans avoir de problème de collisions de noms.

III-D - Conclusion

Les espaces de noms de PHP 5.3 sont un ajout bienvenu dans le langage. Ils aident les développeurs à mieux organiser leur code d'une manière cohérente dans une application. Ils vous permettent d'éviter d'utiliser des conventions de nommage pour simuler cette fonctionnalité, ce qui vous permet d'écrire du code plus efficace. Bien qu'ils se soient fait attendre, les espaces de noms sont un ajout bienvenu pour toute application à grande échelle et souffrant de collisions de noms.

IV - Création et utilisation d'archives Phar

Cette section est une traduction de : http://www.ibm.com/developerworks/opensource/library/os-php-5.3new4/

IV-A - Introduction

Dans cette quatrième partie, voyons de près Phar, un format d'archive qui peut être utilisé dans PHP. Il peut être utilisé non seulement pour archiver des fichiers, mais aussi pour envoyer et pour exécuter une application complète depuis un seul fichier. Il peut être utilisé avec PHP au moyen d'une extension du répertoire PECL, mais ce sera une extension officielle de PHP à partir de la version 5.3.

Le concept des archives Phar provient de la technologie d'archives JAR de Java™, qui permet d'empaqueter une application dans un fichier unique contenant tout le nécessaire pour l'exécuter. C'est différent du concept des exécutables uniques habituellement produits par les langages comme le C, dans la mesure où le fichier est en réalité une archive et non une application compilée. Ainsi, l'archive JAR contient en réalité les fichiers constituant l'application, qui peuvent être rendus impénétrables pour des raisons de sécurité. L'extension Phar est fondée sur un concept similaire, mais elle est conçue davantage pour l'environnement Web de PHP. De plus, à l'inverse des archives JAR, les archives Phar peuvent être utilisées par PHP lui-même et elles ne nécessitent pas d'outil externe pour les créer ou pour les lire.

L'extension Phar n'est pas totalement nouvelle pour PHP. Elle était initialement écrite en PHP sous le nom de PHP_Archive, et fut ajoutée au répertoire PEAR en 2005. Toutefois, une solution à ce problème, écrite en PHP, est trop lente dans le monde réel, c'est pourquoi PHP_Archive fut réécrite en extension C en 2007. Dans le même temps, le support d'ArrayAccess de la SPL fut ajouté pour parcourir une archive Phar. Depuis lors, des efforts considérables ont été produits pour améliorer les performances des archives Phar.

IV-B - Créer une archive Phar

Pour créer un fichier Phar, il faut suivre certaines étapes. Toutes nécessitent des commandes PHP sous une forme ou sous une autre, puisqu'il n'existe aucun outil autonome pour créer ces archives. De plus, afin de créer et de modifier des fichiers Phar, le paramètre phar.readonly de php.ini doit être mis à la valeur zéro. Ce paramètre n'est pas requis pour ouvrir ou pour référencer des fichiers d'une archive Phar dans PHP.

Voyons les étapes nécessaires pour créer une archive Phar qui puisse être utilisée pour lancer une application. Cette application sera conçue pour être chargée directement depuis le serveur Web ou la ligne de commande. La première étape est de créer le fichier Phar, ce que nous allons faire en créant l'objet Phar avec lequel nous allons travailler pour cet exemple dans Listing 1. La référence à l'objet vous permettra de contrôler tous les aspects de l'archive Phar.

Listing 1. Création de l'objet Phar

$p = new Phar(
'/chemin/vers/mon.phar',
Phar::CURRENT_AS_FILEINFO | Phar::KEY_AS_FILENAME,
'mon.phar');

$p->startBuffering();

Le premier paramètre du constructeur est le chemin vers l'emplacement de sauvegarde du fichier Phar. Le second paramètre transmet tous les paramètres à la classe parent RecursiveDirectoryIterator. Le troisième paramètre est un alias pour la manière dont ce fichier Phar est référencé dans le contexte des flux. Ainsi, pour le Listing 1, vous pouvez appeler un fichier de ce Phar grâce à phar://mon.phar. Vous pouvez également appeler la méthode Phar::startBuffering() pour mettre en tampon les modifications faites à l'archive jusqu'à ce que vous appeliez la commande Phar::stopBuffering(). Bien qu'il ne soit pas nécessaire de le faire, cela améliore les performances de création et de modification de l'archive puisque cela évite de modifier le fichier chaque fois que votre script le modifie.

Par défaut, le Phar créé utilisera le format de fichier fondé sur Phar. Vous pouvez également utiliser un format ZIP ou TAR pour le fichier Phar en le convertissant dans ce format, comme indiqué en Listing 2.

Listing 2. Changer le format d'enregistrement à ZIP

$p = $p->convertToExecutable(Phar::ZIP);

Il y a des avantages et des inconvénients à modifier le format de l'archive. L'avantage principal est la capacité d'inspecter le contenu de l'archive avec n'importe quel outil pour traiter des fichiers ZIP ou TAR. Cependant, utiliser une archive Phar qui n'utilise pas le format d'archive natif basé sur Phar ne nécessite pas l'utilisation de l'extension Phar pour charger l'archive, contrairement aux archives formatées en ZIP ou en TAR.

Ensuite, vous avez besoin de définir le fichier bouchon, qui est le premier code appelé lorsque le fichier Phar est chargé.

IV-C - Le fichier bouchon de Phar

Le fichier bouchon est simplement un segment de code très court qui est exécuté au départ lorsque le fichier Phar est lancé, et il se termine par la commande __HALT_COMPILER(). Le Listing 3 est un fichier bouchon typique.

Listing 3. Fichier bouchon pour Phar

<?php
Phar::mapPhar();
include 'phar://monphar.phar/index.php';
__HALT_COMPILER();

L'appel de la méthode Phar::mapPhar() montré ci-dessus initialise l'archive Phar en lisant le manifeste. Vous devez le faire avant de référencer des fichiers à l'intérieur de l'archive au moyen du gestionnaire de flux phar://. Le fichier à charger initialement est ce que votre application chargerait en premier dans une situation normale ; dans cet exemple : index.php.

La manière d'ajouter ce fichier bouchon dépend du format d'archive utilisé. Pour des archives basées sur le format Phar, utilisez la méthode Phar::setStub() qui admet un seul paramètre : le code PHP à mettre dans le bouchon, en tant que chaîne. Le Listing 4 illustre cette approche.

Listing 4. Utiliser Phar::setStub() pour créer le fichier bouchon

$p->setStub("<?php Phar::mapPhar();
include 'phar://monphar.phar/index.php'; __HALT_COMPILER(); ?>");

Si vous n'avez pas prévu de faire davantage de choses avec le bouchon que de rediriger vers une page index.php, vous pouvez utiliser la méthode raccourci Phar::createDefaultStub() afin de créer le bouchon à votre place. Pour cela, vous aurez simplement besoin de transmettre le nom du fichier que vous désirez inclure dans le fichier bouchon. Dans le Listing 5, nous réécrivons l'appel à la méthode Phar::setStub() pour utiliser cette méthode raccourci.

Listing 5. Utiliser Phar::createDefaultStub() pour créer le fichier bouchon

$p->setStub($p->createDefaultStub('index.php'));

Un second argument facultatif de la méthode Phar::createDefaultStub() permet d'inclure un fichier différent si le Phar est chargé depuis un serveur Web. C'est pratique dans le cas où votre application est conçue pour être utilisée en lignes de commandes et dans un contexte de navigateur Web.

Pour les implémentations basées sur ZIP et TAR, vous enregistrez le contenu du bouchon ci-dessus dans le fichier .phar/stub.php, plutôt que d'utiliser la commande setStub().

IV-D - Ajouter des fichiers à l'archive

L'objet Phar utilise l'interface ArrayAccess de la SPL pour permettre l'accès au contenu de l'archive comme un tableau, ce qui donne l'opportunité d'utiliser de nombreuses manières d'ajouter des fichiers à l'archive. La manière la plus simple est d'utiliser directement l'interface ArrayAccess.

Listing 6. Ajouter des fichiers à l'archive

$p['fichier.txt'] = 'Ceci est un fichier texte';
$p['index.php'] = file_get_contents('index.php');

Le Listing 6 montre que le nom de fichier est précisé comme clef, et le contenu comme valeur. Vous pouvez utiliser la fonction file_get_contents() pour donner comme valeur le contenu d'un fichier existant. Cela laisse un peu de flexibilité sur la manière d'ajouter un fichier à l'archive, soit en référençant un fichier existant soit en construisant un fichier à la volée. Cette dernière approche est utile en tant qu'élément d'un script de compilation d'une application.

Si le fichier que vous enregistrez dans l'archive Phar est gros, vous pouvez comprimer le fichier dans l'archive en utilisant une compression gzip ou bzip2, respectivement au moyen des méthodes PharFileInfo::setCompressedGZ() et PharFileInfo::setCompressedBZIP2(). Dans le Listing 7, nous allons comprimer une archive en utilisant bzip2.

Listing 7. Comprimer une archive en utilisant bzip2

$p['gros.txt'] = 'Ceci est un gros fichier texte';
$p['gros.txt']->setCompressedBZIP2();

Pour comprimer un fichier ou pour utiliser une archive contenant un fichier comprimé, l'extension bzip2 ou zlib (pour les archives comprimées en gz) doit être activée dans l'installation PHP.

Admettons que vous souhaitiez ajouter de nombreux fichiers à l'archive. Les ajouter un à un en utilisant l'interface ArrayAccess peut devenir fastidieux, ainsi il y a plusieurs raccourcis pour le faire. Un moyen est d'utiliser la méthode Phar::buildFromDirectory(), qui traverse un répertoire défini et qui ajoute les fichiers qui s'y trouvent. Elle permet également de filtrer les fichiers à ajouter en transmettant un second paramètre avec le modèle d'expression régulière validant les fichiers à ajouter à l'archive. Le Listing 8 montre comment utiliser cela.

Listing 8. Ajouter des fichiers à une archive en utilisant Phar::buildFromDirectory()

$p->buildFromDirectory('/chemin/vers/les/fichiers', './\.php$/');

Le Listing 8 ajoute à l'archive Phar tous les fichiers PHP du répertoire indiqué. Vous pouvez alors revenir à l'utilisation de l'interface ArrayAccess si vous souhaitez apporter des modifications aux fichiers ajoutés, tel que les marquer pour une compression.

Vous pouvez également utiliser la méthode Phar::buildFromIterator() pour ajouter des fichiers en utilisant un itérateur. Deux types d'itérateurs sont supportés : ceux qui lient le nom de fichier au sein du Phar au nom de fichier sur le disque, et ceux qui renvoient des objets SplFileInfo. Un opérateur compatible est RecursiveDirectoryIterator, utilisé ci-dessous pour ajouter à l'archive les fichiers d'un répertoire.

Listing 9. Ajouter des fichiers à une archive au moyen de Phar::buildFromIterator()

$p->buildFromIterator(new RecursiveIteratorIterator
(new RecursiveDirectoryIterator('/chemin/vers/les/fichiers')), '/chemin/vers/les/fichiers');

La méthode Phar::buildFromIterator() accepte l'itérateur lui-même comme seul argument. Dans l'exemple ci-dessus, nous avons englobé l'objet RecursiveDirectoryIterator dans un objet RecursiveIteratorIterator, ce dernier donnant le type compatible d'itérateur dont la méthode Phar::buildFromIterator() a besoin.

Nous avons créé une archive Phar qui peut être utilisée dans n'importe quelle application. Voyons comment utiliser facilement cette archive.

IV-E - Utiliser des archives Phar

L'avantage des fichiers Phar est à quel point ils sont faciles à intégrer dans n'importe quelle application, surtout si vous avez utilisé le format d'archive basé sur Phar. Dans ce cas, vous n'avez pas même besoin de l'extension Phar, puisque PHP sait nativement charger le fichier et en extraire le contenu. Les archives basées sur ZIP et TAR requièrent le chargement de l'extension Phar.

Les archives Phar sont conçues pour être incluses dans une application telles que n'importe quel fichier, ce qui rend leur utilisation très simple pour les développeurs déjà habitués à inclure du code tiers. Voyons comme il est facile d'intégrer un Phar dans notre application.

IV-E-1 - Intégrer le code d'une archive Phar dans votre application

Le moyen le plus facile d'intégrer du code d'une archive Phar est de simplement inclure l'archive Phar, puis d'inclure le fichier de l'archive Phar que vous souhaitez utiliser. Le gestionnaire de flux phar:// peut être utilisé pour avoir accès à un fichier situé dans une archive Phar chargée, comme indiqué ci-dessous :

Listing 10. Charger du code d'une archive Phar

include 'monphar.phar';
include 'phar://monphar.phar/fichier.php';

La première inclusion charge l'archive monphar.phar, ainsi que le code défini dans le fichier bouchon. La seconde inclusion utilise le gestionnaire de flux pour ouvrir l'archive Phar et se charge uniquement d'inclure le fichier indiqué dans l'archive. Notons qu'il n'est pas nécessaire d'inclure l'archive Phar elle-même avant d'inclure un fichier de l'archive.

IV-E-2 - Exécuter une application PHP depuis une archive Phar

Une fonctionnalité intéressante des archives Phar est la capacité d'empaqueter une application entière dans une archive Phar et de la distribuer de cette manière. L'avantage de cette approche est que le déploiement devient plus simple sans pénalité de performances, grâce à plusieurs améliorations de Phar en PHP 5.3. Cependant, lorsque vous développez une application pour être exécutée depuis un Phar, voici quelques considérations à prendre en compte relativement à la conception de l'application :

1. Tout fichier qu'il est nécessaire de créer et qui est spécifique à une instance de l'application, comme les fichiers de configuration, ne peut faire partie de l'archive, de telle sorte que vous devrez les écrire à un emplacement distinct, mais accessible. Il en vaut de même si votre application crée des fichiers de cache lors de son exécution ;

2. Pour une portabilité maximale, vous devriez vous tenir au format d'archive basé sur Phar et sans compression. Les formats basés sur ZIP et TAR ont besoin de l'extension Phar installée avec PHP, tandis que le format d'archive basé sur Phar peut être utilisé même si l'extension Phar n'est pas installée ;

3. Toute référence à des fichiers dans l'application doit être changée pour utiliser le gestionnaire de flux phar:// avec le nom de l'archive, comme nous l'avons vu dans la section précédente.

phpMyAdmin est une application particulièrement populaire qui a été empaquetée en Phar afin d'être utilisée comme exemple de la simplicité d'utilisation de Phar. Elle a été entièrement conçue pour être exécutée depuis une archive Phar, mais elle propose néanmoins la possibilité d'écrire son fichier de configuration à l'extérieur de l'archive Phar.

IV-F - Conclusion

Les archives Phar sont un ajout très utile à PHP 5.3. Elles donnent la capacité d'empaqueter du code PHP dans une archive, ce qui peut être utile pour distribuer une application ou une bibliothèque dans un fichier unique. L'archive Phar peut être chargée facilement depuis un fichier PHP au moyen d'une instruction include ou require, ou bien elle peut être exécutée directement depuis le navigateur ou la ligne de commandes en appelant l'archive par son nom.

V - Migration depuis PHP 5.2

Cette section est une traduction de : http://www.ibm.com/developerworks/opensource/library/os-php-5.3new5/

V-A - Introduction

Dans cette dernière partie de la série, nous voyons les éléments à prendre en considération lors de la migration depuis PHP 5.2. Ce sont des modifications qui cassent la compatibilité avec le code existant ainsi que des fonctionnalités déconseillées dans PHP 5.3 et pour suppression dans des versions ultérieures. Certaines améliorations de PHP sont également abordées.

Cette série s'est concentrée sur les nouvelles fonctionnalités de PHP 5.3 telles que les espaces de noms, les fermetures, la gestion des objets, la programmation orientée objet et Phar. Tandis que ces nouvelles fonctionnalités étincelantes sont un ajout attrayant pour le langage, PHP 5.3 a également été conçu pour mieux aligner PHP sur les autres langages. Cette version étoffe la version populaire et stable, PHP 5.2, et améliore le langage pour le rendre plus puissant. Dans cet article, nous voyons les modifications et les considérations à évaluer lors de la mise à jour depuis 5.2.

V-B - Changements syntaxiques

Des ajouts au langage, comme les espaces de noms et les fermetures (cf. parties II et III), ont ajouté des mots réservés supplémentaires. Depuis PHP 5.3, namespace ne peut plus être utilisé comme identifiant. La classe Closure est désormais une classe réservée, mais c'est encore un identifiant valide. Le Listing 1 montre des exemples d'instructions qui ne fonctionnent plus en PHP 5.3 à cause des mots réservés supplémentaires.

Listing 1. Instructions PHP incorrectes

// la définition suivante de fonction lance une erreur fatale PHP 5.3,
// alors qu'elle est parfaitement valide en PHP 5.2
function namespace()
{
....
}

// de même avec la définition de cette classe
class Closure
{
....
}

Le support de l'instruction goto a également été ajouté en PHP 5.3. Désormais, goto est un mot réservé. Les instructions goto ne sont pas fréquentes dans les langages modernes (vous vous souvenez probablement de les avoir utilisées en BASIC), mais il y a occasionnellement des situations dans lesquelles elles sont utiles. Le Listing 2 montre un exemple de leur fonctionnement.

Listing 2. L'instruction goto en PHP

echo "Ce texte est affiché";
goto a;

echo "Ce texte est évité";

a:
echo "Ce texte est affiché";

Un cas d'utilisation possible de l'instruction goto est de sortir de boucles et de conditionnelles à forte imbrication. Cela rend le code bien plus facile à lire.

V-C - Modifications aux fonctions et méthodes

Bien qu'il n'y ait pas de modifications majeures aux fonctions et aux méthodes en PHP 5.3, il y a quelques améliorations pour aider avec des problèmes connus de PHP et pour améliorer les performances. Cette section présente quelques-uns des changements les plus remarquables.

Dans les versions précédentes de PHP, les fonctions de tableaux atsort, natcasesort, usort, uasort, uksort, array_flip et array_unique acceptent des objets en paramètres à la place de tableaux. Ce n'est plus possible en PHP 5.3, vous devez ainsi convertir d'abord les objets en tableaux. Le Listing 3 montre comment modifier votre code.

Listing 3. Modifier le code pour convertir les objets en tableaux pour certaines fonctions

$obj = new stdClass;
$obj->a = '1';
$obj->b = '2';
$obj->c = '3';

print_r(array_flip($obj)); // fonctionne en PHP 5.2 mais PAS en PHP 5.3

print_r(array_flip((array) $obj)); // fonctionne en PHP 5.2 et 5.3

Les méthodes magiques de classes sont désormais bien plus strictes. Les méthodes suivantes doivent avoir une visibilité publique :

- __get

- __set

- __isset

- __unset

- __call

Comme contournement de cette modification, vous pouvez utiliser la nouvelle méthode magique __callStatic() dans les situations où __call() était utilisée en contexte statique. Les arguments obligatoires de ces méthodes sont renforcés et ils doivent être présents, à l'exception de la méthode magique __toString() qui n'accepte aucun paramètre. Le Listing 4 montre comment utiliser ces méthodes ainsi que leurs paramètres obligatoires.

Listing 4. Utiliser les méthodes magiques

class Foo
{
public function __get($clef) {} // doit être publique et avoir un paramètre
public function __set($clef, $val) {} // doit être publique et avoir deux paramètres
public function __toString() {} // doit être publique et ne pas avoir de paramètre
}

Plusieurs fonctions qui n'étaient jusque-là pas supportées par PHP sous Windows sont présentes depuis PHP 5.3. Par exemple, la fonction getopt() est conçue pour traiter les options en vue d'appeler un script en ligne de commande. Les fonctions d'encodage et de décodage des adresses Internet, inet_ntop() et inet_pton(), fonctionnent également sous Windows, ainsi que certaines fonctions mathématiques comme asinh(), acosh(), atanh(), loglp() et expml().

V-D - Modifications d'extensions

La bibliothèque C d'extensions PHP (PECL – PHP Extension C Library) a été le lieu d'élevage de nouvelles extensions en PHP. Lorsqu'une extension est mature, stable et qu'elle est perçue comme une fonction utile en tant que part de la distribution noyau, elle est souvent ajoutée au moment d'une version majeure. Dans cette optique, à partir de PHP 5.3, les extensions suivantes font désormais partie de la distribution standard de PHP :

FileInfo

Donne des fonctions qui aident à la détection du type de contenu et à l'encodage d'un fichier en étudiant certaines séquences de caractères magiques dans le fichier.

Intl

Une interface de programmation autour de la bibliothèque ICU (International Components for Unicode), des fonctions pour le support d'Unicode et de globalisation.

Phar

Un outil d'archivage PHP étudié en section IV.

mysqlnd

Un pilote natif PHP pour avoir accès aux bases de données MySQL, c'est un remplacement de l'extension précédente pour MySQL et MySQLi qui utilisait la bibliothèque libmysql.

SQLite3

Une bibliothèque pour utiliser les bases de données SQLite v3.

Lorsqu'une extension n'est plus maintenue, ou lorsqu'il est jugé qu'elle ne mérite plus de faire partie de la distribution noyau de PHP, il arrive qu'elle soit déplacée vers PECL. Lors des remaniements pour PHP 5.3, les extensions suivantes ont été enlevées de la distribution standard de PHP et elles sont désormais maintenues par PECL :

ncurses

Une émulation de curses, qui est utilisée pour afficher des éléments visuels dans la console.

fpdf

Permet la construction et l'utilisation de formulaires ainsi que de données de formulaires dans des documents PDF.

dbase

Permet d'écrire et de lire des fichiers compatibles avec le format dbase.

fbsql

Permet l'accès à des bases de données sur serveurs Frontbase.

ming

Une bibliothèque open source qui permet de créer des animations Flash 4.

L'extension Sybase a été supprimée entièrement, elle est maintenant remplacée par l'extension sybase_ct. Cette dernière est entièrement compatible avec l'extension antérieure, elle est prévue pour constituer un remplacement transparent. La nouvelle fonction utilisera les bibliothèques clientes de Sybase qu'il faut installer sur le serveur Web.

V-E - Modifications de compilation

Avec les efforts conséquents associés au perfectionnement de la procédure de compilation de PHP 5.3, il est plus facile de compiler PHP sur toutes les plateformes. Afin de maintenir la cohésion entre les compilations de PHP et de fournir un ensemble garanti de composants dans PHP, les extensions PCRE, Réflexion et la SPL ne peuvent plus être désactivées de la compilation. Vous pouvez développer des applications qui utilisent ces extensions avec l'assurance qu'elles seront disponibles.

L'an dernier, une nouvelle équipe a pris en charge la compilation de PHP pour Windows. À partir de PHP 5.3, l'équipe donnera diverses améliorations aux utilisateurs de Windows. Les nouvelles compilations cibleront l'architecture 586 (Intel® Pentium® ou ultérieur) et nécessitent Windows 2000/XP ou ultérieur, supprimant ainsi le support de Windows 98/NT et antérieurs. PHP sera compilé avec Microsoft® Visual Studio® 2008 et pour des architectures x86-64 bits. Cela donne des améliorations de performances en travaillant avec FastCGI sur le serveur Web Microsoft IIS ou avec Apache compilé avec le même compilateur et pour la même architecture. L'installateur pour Windows est également amélioré afin de mieux configurer PHP avec le serveur Web Microsoft IIS. L'équipe a lancé un nouveau site spécifique à PHP pour Windows.

V-F - Modifications .ini

Une fonctionnalité importante de PHP est que son comportement peut être configuré au moyen d'un fichier .ini. Dans PHP 5.3, certaines directives problématiques de ce fichier ont été supprimées, telles que le paramètre zend.ze1_compatibility_mode. Vous avez désormais bien plus de latitude à l'utilisation de ce fichier.

Il y a deux améliorations majeures au fichier php.ini :

- vous pouvez avoir des variables dans le fichier php.ini. C'est très pratique pour supprimer la redondance dans le fichier, et il devient plus facile de mettre à jour le fichier si des modifications sont nécessaires. Le Listing 5 en montre un exemple ;

- vous pouvez faire des configurations php.ini par site ou par répertoire, de manière analogue à ce qu'il se fait avec les fichiers de configuration Apache. L'avantage ici est que la syntaxe devient cohérente à travers toutes les API différentes qui permettent d'exécuter PHP. Le Listing 6 montre comment cela fonctionne.

Listing 5. Des variables dans le fichier php.ini

foo = bar

[section]
newfoo = ${foo}
; foo et newfoo ont la même valeur.

Listing 6. Configuration .ini par site ou par répertoire

[PATH=/var/www/site1]

; les directives de cette section sont valables uniquement pour les fichiers PHP sous le répertoire /var/www/site1

[HOST=www.example.com]

; les directives de cette section sont valables uniquement pour des fichiers PHP demandés depuis le site www.example.com.

Vous pouvez également créer ces directives .ini dans un fichier spécifique à un utilisateur, dans le système de fichiers lui-même, de la même manière que vous le feriez avec le serveur Web Apache HTTP. Le nom par défaut de ce fichier est précisé par la directive user_ini.filename. La fonctionnalité peut être désactivée en donnant une valeur vide à cette directive. Toute directive par site ou par répertoire peut être surchargée dans un fichier .ini de l'utilisateur.

[NDT : Cette nouvelle fonctionnalité n'est disponible que pour PHP en tant que CGI ou FastCGI, pas en tant que module d'Apache.]

V-G - Éléments marqués pour suppression (deprecated)

PHP 5.3 commence officiellement à déconseiller l'utilisation d'anciennes fonctions qui ne seront plus disponibles dans de prochaines versions de PHP. Lorsque vous utiliserez ces fonctions, une erreur E_DEPRECATED sera émise. Les fonctions suivantes sont déconseillées en PHP 5.3 :

- Ticks (declare(ticks=N) et register_tick_function()), qui étaient conçus pour lancer un appel de fonction toutes les N instructions exécutées par l'interpréteur dans le bloc declare(). Ils sont retirés à cause de nombreux problèmes dans leur fonctionnement et, car la fonctionnalité n'est pas utilisée très souvent ;

- define_syslog_variables(), qui initialise toutes les variables en relation avec le journal système. Cette fonction n'est pas requise, car les constantes qu'elle définit sont déjà définies globalement. Le retrait de cet appel de fonction devrait être le seul effort nécessaire ;

- les fonctions d'expressions régulières ereg. Il est recommandé d'utiliser les fonctions d'expressions régulières PCRE à la place, dans la mesure où elles sont bien plus rapides et plus homogènes avec les expressions régulières utilisées dans d'autres langages et applications. Le support des fonctions ereg est supprimé afin que PHP puisse être standardisé avec un seul moteur d'expressions régulières.

Il est recommandé de prévoir de vous défaire de ces fonctions en PHP 5.3. Les versions ultérieures de PHP retireront le support des éléments ci-dessus.

[NDT Les modes E_DEPRECATED et E_USER_DEPRECATED ont été ajoutés en PHP 5.3.]

V-H - Conclusion

PHP 5.3 a de nombreuses nouvelles fonctionnalités et a « nettoyé » divers éléments. Il y a certains problèmes d'incompatibilité avec l'ancienne syntaxe. Cet article donne des conseils pour migrer votre application Web vers PHP 5.3. Pour les derniers détails sur PHP 5.3, veuillez vous rendre sur le Wiki PHP, qui comporte des remarques sur tout autre changement pouvant affecter votre application.

[NDT : Je remercie ram-000, Julien Pauli et metagoto pour leur relecture attentive, ainsi que les contributeurs du forum qui n'ont pas attendu pour me faire corriger l'article en fonction des dernières évolutions de PHP 5.3 : Commentez ]