Traits
Depuis PHP 5.4.0, PHP supporte une manière de réutiliser le code appelée Traits.
Les traits sont un mécanisme de réutilisation de code dans un langage à héritage simple tel que PHP. Un trait tente de réduire certaines limites de l'héritage simple, en autorisant le développeur à réutiliser un certain nombre de méthodes dans des classes indépendantes. La sémantique entre les classes et les traits réduit la complexité et évite les problèmes typiques de l'héritage multiple et des Mixins.
Un trait est semblable à une classe, mais il ne sert qu'à grouper des fonctionnalités d'une manière intéressante. Il n'est pas possible d'instancier un Trait en lui-même. C'est un ajout à l'héritage traditionnel, qui autorise la composition horizontale de comportements, c'est à dire l'utilisation de méthodes de classe sans besoin d'héritage.
Exemple #1 Exemple d'utilisation de Trait
<?php
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>
Précédence
Une méthode héritée depuis une classe mère est écrasée par une méthode issue d'un Trait. L'ordre de précédence fait en sorte que les méthodes de la classe courante écrasent les méthodes issues d'un Trait, elles-mêmes surchargeant les méthodes héritées.
Exemple #2 Exemple avec l'ordre de précédence
Une méthode héritée depuis la classe de base est écrasée par celle provenant du Trait. Ce n'est pas le cas des méthodes réelles, écrites dans la classe de base.
<?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();
?>
L'exemple ci-dessus va afficher :
Hello World!
Exemple #3 Autre exemple d'ordre de précédence
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
class TheWorldIsNotEnough {
use HelloWorld;
public function sayHello() {
echo 'Hello Universe!';
}
}
$o = new TheWorldIsNotEnough();
$o->sayHello();
?>
L'exemple ci-dessus va afficher :
Hello Universe!
Multiples Traits
Une classe peut utiliser de multiples Traits en les déclarant avec le mot-clé use, séparés par des virgules.
Exemple #4 Utilisation de plusieurs Traits
<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
}
trait World {
public function sayWorld() {
echo 'World';
}
}
class MyHelloWorld {
use Hello, World;
public function sayExclamationMark() {
echo '!';
}
}
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>
L'exemple ci-dessus va afficher :
Hello World!
Résolution des conflits
Si deux Traits insèrent une méthode avec le même nom, une erreur fatale est levée si le conflit n'est pas explicitement résolu.
Pour résoudre un conflit de nommage entre des Traits utilisés dans la même classe, il faut utiliser l'opérateur insteadof pour choisir une des méthodes en conflit.
Puisque ce principe ne permet que d'exclure des méthodes, l'opérateur as peut être utilisé pour permettre l'inclusion d'une des méthodes conflictuelles sous un autre nom. Notez que l'opérateur as ne renome pas la méthode et n'affecte pas d'autres méthodes non plus.
Exemple #5 Résolution des conflits
Dans cet exemple, la classe Talker utilise les traits A et B. Comme A et B ont des méthodes conflictuelles, on indique que l'on souhaite utiliser la variante de smallTalk depuis le trait B, et la variante de bigTalk depuis le trait A.
La classe Aliased_Talker utilise l'opérateur as pour être capable d'utiliser l'implementation bigTalk de B sous un alias supplémentaire talk.
<?php
trait A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
}
trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
}
class Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}
class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
?>
Note:
Antérieur à PHP 7.0, définir une propriété dans une classe avec le même nom que dans un trait émétait une erreur
E_STRICT
si la définition de classe était compatible (même visibilité et valeur initiale).
Changer la visibilité des méthodes
En utilisant la syntaxe as, vous pouvez aussi ajuster la visibilité de la méthode dans la classe qui l'utilise.
Exemple #6 Changer la visibilité des méthodes
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
// Modification de la visibilité de la méthode sayHello
class MyClass1 {
use HelloWorld { sayHello as protected; }
}
// Utilisation d'un alias lors de la modification de la visibilité
// La visibilité de la méthode sayHello n'est pas modifiée
class MyClass2 {
use HelloWorld { sayHello as private myPrivateHello; }
}
?>
Traits Composés depuis d'autres Traits
Tout comme les classes peuvent utiliser des traits, d'autres traits le peuvent aussi. Un trait peut donc utiliser d'autres traits et hériter de tout ou d'une partie de ceux-ci.
Exemple #7 Traits Composés depuis d'autres Traits
<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
}
trait World {
public function sayWorld() {
echo 'World!';
}
}
trait HelloWorld {
use Hello, World;
}
class MyHelloWorld {
use HelloWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>
L'exemple ci-dessus va afficher :
Hello World!
Méthodes abstraites dans les Traits
Les traits supportent l'utilisation de méthodes abstraites afin d'imposer des contraintes aux classes sous-jacentes.
Une classe concrète satisfait ces conditions en définissant une méthode concrète avec le même nom ; sa signtaure peut être différente.
Exemple #8 Obligations requises par les méthodes abstraites
<?php
trait Hello {
public function sayHelloWorld() {
echo 'Hello'.$this->getWorld();
}
abstract public function getWorld();
}
class MyHelloWorld {
private $world;
use Hello;
public function getWorld() {
return $this->world;
}
public function setWorld($val) {
$this->world = $val;
}
}
?>
Attributs statiques dans les Traits
Traits peut définir à la fois des membres statiques, et des méthodes statiques.
Exemple #9 Variables statiques
<?php
trait Counter {
public function inc() {
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
}
class C1 {
use Counter;
}
class C2 {
use Counter;
}
$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>
Exemple #10 Méthodes statiques
<?php
trait StaticExample {
public static function doSomething() {
return 'Doing something';
}
}
class Example {
use StaticExample;
}
Example::doSomething();
?>
Propriétés
Les traits peuvent aussi définir des propriétés.
Exemple #11 Définir des propriétes
<?php
trait PropertiesTrait {
public $x = 1;
}
class PropertiesExample {
use PropertiesTrait;
}
$example = new PropertiesExample;
$example->x;
?>
Si un trait définit une propriété, alors la classe ne peut pas définir une propriété de même nom sauf si elle est compatible (même visibilité et valeur initiale), sinon une erreur fatale est émise. Avant PHP 7.0.0, définir une propriété dans une classe avec la même visibilité et valeur initiale que dans le trait, émétait une notice E_STRICT.
Exemple #12 Résolution des conflits
<?php
trait PropertiesTrait {
public $same = true;
public $different = false;
}
class PropertiesExample {
use PropertiesTrait;
public $same = true; // Autorisé à partir de PHP 7.0.0; notice E_STRICT précédemment
public $different = true; // Fatal error
}
?>
Version en cache
21/11/2024 22:41:17 Cette version de la page est en cache (à la date du 21/11/2024 22:41:17) afin d'accélérer le traitement. Vous pouvez activer le mode utilisateur dans le menu en haut pour afficher la dernère version de la page.Document créé le 30/01/2003, dernière modification le 26/10/2018
Source du document imprimé : https://www.gaudry.be/php-rf-language.oop5.traits.html
L'infobrol est un site personnel dont le contenu n'engage que moi. Le texte est mis à disposition sous licence CreativeCommons(BY-NC-SA). Plus d'info sur les conditions d'utilisation et sur l'auteur.
Références
Ces références et liens indiquent des documents consultés lors de la rédaction de cette page, ou qui peuvent apporter un complément d'information, mais les auteurs de ces sources ne peuvent être tenus responsables du contenu de cette page.
L'auteur de ce site est seul responsable de la manière dont sont présentés ici les différents concepts, et des libertés qui sont prises avec les ouvrages de référence. N'oubliez pas que vous devez croiser les informations de sources multiples afin de diminuer les risques d'erreurs.