A quoi servent les traits en PHP

#1 Qu'est-ce qu'un trait ? open

Un trait fait partie d'un mécanisme qui sert à incorporer du code dans une classe. Ci-dessous, je mets du code dans le trait BarTrait et ensuite, je l'incorpore dans la classe Foo.

Nommez votre trait en utilisant le suffixe Trait si vous voulez respecter les PSRs.

Dit comme ça, ce mécanisme fait penser à un require. On va voir que c'est plus élaboré que ça, car il y a un mécanisme d'héritage. De plus, il est possible d'incorporer plusieurs traits, ce qui fait que l'héritage devient multiple.

Ci-dessous, pour l'explication, je laisse tomber les PSRs. :

  1. Je déclare un trait A qui contient une méthode fa.
  2. Je déclare un trait B qui contient une méthode fb.
  3. Je déclare un trait C qui incorpore le trait A et le trait B.
  4. Je déclare une classe Foo qui incorpore le trait C (* pas A et B).
  5. J'instancie Foo et je vois que j'ai accès à fa et fb qui "viennent" du trait A et du trait B. Donc il y a bien un mécanisme d'héritage et de plus, il est multiple.

La classe Foo hérite du trait C qui lui-même hérite des traits A et B.

Pour autant, les traits ne sont pas des classes, car ils ne peuvent pas être instanciés et donc ne construisent aucun objet.

#2 Que peut-on mettre dans un trait ? open

Dans un trait, vous pouvez mettre des propriétés, des propriétés statiques, des constantes (* depuis PHP 8.2), des méthodes, des méthodes statiques. Il y a d'autres possibilités que je n'étudierai pas ici et que vous pouvez trouver dans la doc.

Ci-dessous, il faut voir une chose. J'utilise $this dans le trait A alors que $this pointe sur une instance et que le trait ne peut pas être instancié 🙃. Alors, il faut bien comprendre que ce $this pointera sur une instance de la classe qui utilisera le trait.

Résultats exécution

#3 Gestion des collisions avec instead et as open

Etant donnée que l'on a une possibilité d'héritage multiple, hé bien, on a des risques de collisions. On va voir comment gérer ces collisions.

Ci-dessous, j'ai une méthode foo() qui est présente à la fois dans le trait A et le trait B. La classe Bar utilise ces deux traits et se retrouve avec deux méthodes foo().

Ce qu'il faut faire pour gérer la collision c'est :

  1. D'abord choisir quelle est la méthode foo() qui va garder son nom. Ci-dessous, j'écris A::foo insteadof B; (* A au lieu de B). Je choisis de garder le foo() du trait A.
  2. Ensuite, j'écris B::foo as qux;. Ca veut dire que pour avoir le foo() du trait B, il faut utiliser qux().
PHP Collision entre deux traits

#4 Règles de priorité sur collision open

Il y a d'autres situations qui peuvent se produire et qui ne seront pas gérables avec insteadof et as. Dans ce cas, ce sont des règles de priorité qui vont s'appliquer.

Ci-dessous, la classe Fille reçoit en héritage la méthode foo() de la classe Mere. Elle reçoit également la même méthode foo() depuis le trait A qu'elle utilise.

PHP va choisir la méthode venant du trait.

PHP Priorité au trait

Ci-dessous, j'ai une classe Fille qui reçoit une méthode foo() de la classe Mere et d'un trait A. Ici, la classe Fille surcharge la méthode foo(). Dans ce cas, PHP va choisir le foo() de la classe Fille.

PHP Priorité à la classe fille

Ci-dessous, la classe Bar possède la méthode foo() et reçoit de trait A une autre méthode foo(). PHP va choisir celui de la classe Bar.

PHP Priorité à la classe Bar

Politique de confidentialité

Mentions Légales