L'utilisation des "Trait" en PHP
Voici un type de classe dont j'ai fais la découverte dans le cadre de mon boulot et dont je n'avais jamais compris le sens car c'est un sujet qui n'est pas abordé dans les formations ni dans les ressources qu'on trouve habituellement sur le net (ça parle plutôt des interfaces, les factory, les adaptateurs, etc...).
Pour être assez concis, un Trait est une classe qui va se comporter comme une classe qui va s'hériter, mais à la différence qu'il est possible d'utiliser plusieurs trait
au sein d'une même classe.
Si je reprends l'exemple de php.net :
<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
Dans cet exemple, la classe MyHelloWorld
hérite de la classe Base
qui contient la méthode sayHello()
qui va echo "Hello ". La classe MyHelloWorld
possède également le trait SayWorld
qui possède cette même méthode sayHello()
mais va récupérer le contenu de la méthode sayHello()
de la classe parente (Base
) puis echo la sienne, ce qui va donner comme résultat Hello World!
quand la méthode sera appelée dans la classe MyHelloWorld
.
Il y a également une autre façon de le faire qui sera peut-être plus lisible :
<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayWorld() {
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello() . $o->sayWorld();
Ce qui sera affiché sera la même chose sauf que cette fois j'ai séparé l'appel aux deux méthodes pour montrer que la méthode sayWorld()
peut être appelée comme si elle faisait partie de la classe MyHelloWorld
au même titre qu'une méthode d'une classe héritée.
On peut également voir un exemple qui est plus proche de la réalité en terme de code :
L'exemple est un peu long mais c'est nécessaire pour la suite. Donc la classe Product
utilise quatre traits AutoIdentifiableTrait
, UuidTrait
, NameableTrait
et TimestampableTrait
. Ces traits ont le contenu suivant :
Cela signifie que la classe Product
aura les propriétés et les méthodes de tous les traits au sein de sa classe. Et vous pourrez utiliser n'importe lequel de ces traits dans une autre classe si vous le souhaitez.
Cependant si vous modifiez un trait, les changements seront répercutés dans toutes les classes utilisant le trait que vous aurez modifié.
Et là vous allez me demander ? "Mais quel est l'intérêt de faire un trait ?". Et la réponse est : ça vous permet de normaliser le format de vos propriétés à travers plusieurs classes par exemple car rien ne vous empêche d'utiliser les traits que nous venons de créer dans une classe User
ou Book
par exemple car cela a les avantages suivants :
- La déclaration est unique, c'est à dire que si vous êtes une faute de frappe ou que vous devez modifier le contenu du trait à travers toutes les classes, il suffit de le faire qu'une seule fois dans celui-ci au lieu de chercher toutes les occurrences dans toutes les classes où c'est utilisé.
- Cela permet d'être certain que ce qui est déclaré dans le trait l'est de manière consistante dans toutes les classes où il est utilisé.
Ensuite si vous avez un traitement particulier à faire qui ne colle pas à celle qui est dans le trait, il suffit de mettre le code dans la classe en question comme d'habitude et de ne pas importer le trait au sein de la classe.
J'espère que cela vous sera utile dans vos développements.