PHP 5.4 offre son lot de nouveautés, dont les Traits. Un trait permet d'injecter dans une classe des méthodes d'une ou plusieurs autres "classes" (des traits):
On voit ici l'intérêt du trait : reporter sur une entité un aspect "fonctionnel" d'une classe. On peut imaginer une classe Car presque vide mais fonctionnelle :
Attention toutefois : les Traits rompent avec les aspects classique de la programmation par Interface (de l'orienté objet donc) ou de la programmation par Contrat :
la classe Car n'implémente PAS une Interface Color ou Selling, elles ne fait que reporter, utiliser, horizontalement.
Ce point est très important et dangereux, car en PHP un principe de base est la verticalité des classes et le respect du principe de substitution de Liskov : un objet qui travaille avec un autre objet Y doit pouvoir continuer à fonctionner de la même façon lorsqu'on substitue à cet objet Y un autre objet Z de même Interface.
Un Trait peut s'assurer de la présence d'une méthode dans la classe
Il est possible de s'assurer dans un Trait de la présence de certaines méthodes dans la classe qui l'utilise :
Portée des méthodes
Il est possible de préciser certaines informations lors de la déclaration du trait dans une classe :
Priorité des Traits
Que faire si une classe utilisent des traits qui contiennent les mêmes méthodes ? Tout est prévu :
Cas pratique : le singleton
Il est temps de voir un cas pratique :-) Il est pratique en PHP de créer une classe abstraite Singleton, que l'on serait tentée d'hériter à chaque fois que l'on a besoin d'un singleton. Malheureusement, PHP ne permet pas l'héritage multiple, et on se prive alors peut-être d'un héritage fonctionnel plus intéressant pour notre classe. L'utilisation des Traits résouts partiellement ce problème :
Pratique non ? (n'oubliez pas qu'un singleton c'est plus que ça, là il ne s'agit que d'un exemple)
Et PHP 5.3 dans tout ça ?
Les Traits n'existent pas en PHP 5.3, pourtant cette version du language risque d'être longtemps utilisée. Il existe une astuce simple pour simuler ces traits en PHP 5.x : la relation de Composition et l'utilisation massive des méthodes magiques :
Nous allons commencer par créer notre classe Child1, en lui donnant un tableau (nommé $_tTraits) qui contiendra la liste des classes dont on souhaite qu'elle puisse les utiliser comme des Traits.
Maintenant, nous allons automatiquement instancier ces classes lors de la construction de l'objet. Ces instances seront stockées, nous nous en serviront pour reporter les actions effectuées sur la classe vers les classes Traits.
Ensuite, nous allons reporter chaque appel de méthode, si elle n'existe pas dans Child1, vers l'un de ses Traits, si cette méthode existe.
Désormais, tout appel de méthode de Child1 est reporté, si elle n'existe pas dans Child1 même, vers une de ses classes Traits. Il est donc possible de surcharger une méthode de ces classes Traits simplement en la déclarant dans Child1.
Enfin, nous allons reporter toutes les lectures d'attributes (accesseurs) vers les attributs des instances des classes Traits:
Pour au final avoir:
Nous avons tout ce qu'il nous faut pour pouvoir utiliser notre classe :
Vous voilà prêt à utiliser les Traits en PHP :-) Pour plus d'info, vous pouvez consulter la RFC de PHP sur les Traits.