Menu

Traits PHP : use, plusieurs traits et insteadof

Un trait PHP est un bloc réutilisable de méthodes et de propriétés que vous copiez dans une classe avec use TraitName;. Utiliser plusieurs traits, résoudre les conflits de noms avec insteadof et as, membres abstraits et statiques d'un trait, quelle méthode l'emporte, et trait, interface ou classe abstraite.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Un trait PHP est un bloc réutilisable de méthodes et de propriétés. Vous le déclarez avec trait Name { ... } et l'importez dans n'importe quelle classe avec use Name; dans le corps de la classe. PHP copie les membres du trait dans la classe, qui fonctionnent exactement comme si vous les y aviez écrits.

User et Robot n'ont pas de parent commun, et pourtant tous deux ont maintenant hello(). Les traits existent pour ce cas : les classes PHP ne peuvent étendre qu'une seule classe, et un trait partage du code latéralement, entre des classes sans lien.

Traits avec des propriétés

Un trait peut apporter des propriétés avec ses méthodes. Les méthodes utilisent $this comme n'importe quelle méthode de la classe, car une fois le trait copié, ce sont des méthodes de la classe :

Une classe ne peut pas déclarer une propriété du même nom qu'une propriété du trait, sauf si les deux déclarations sont identiques (même visibilité, même type et même valeur par défaut) ; sinon c'est une erreur fatale.

Utiliser plusieurs traits

Listez plusieurs traits dans une même instruction use, séparés par des virgules, ou écrivez plusieurs lignes use. La classe reçoit les membres de tous :

Résoudre les conflits avec insteadof et as

Quand deux traits définissent une méthode du même nom, PHP refuse de deviner et s'arrête avec une erreur fatale. Dans un bloc use, insteadof choisit le gagnant, et as garde la méthode perdante sous un autre nom :

Avec un simple use EnglishGreeting, FrenchGreeting; sans bloc, le script s'arrête avant d'afficher quoi que ce soit :

PHP Fatal error:  Trait method FrenchGreeting::greet has not been applied as Host::greet, because of collision with EnglishGreeting::greet in /home/index.php on line 12

as peut aussi changer la visibilité. use Loggable { log as protected; } rend le log() du trait protégé dans cette classe seulement, et use Loggable { log as private writeLog; } ajoute un alias privé.

Membres abstraits et statiques dans un trait

Un trait peut exiger quelque chose de la classe qui l'utilise en déclarant une méthode abstraite. Il peut aussi avoir des méthodes et des propriétés statiques. Chaque classe qui utilise le trait reçoit sa propre copie d'une propriété statique :

Car et Bike comptent séparément, car la propriété statique est copiée dans chaque classe. C'est différent d'une propriété statique déclarée dans une classe parente commune, que tous les enfants partagent ; la page static montre ce cas.

Quelle méthode l'emporte : classe, trait ou parent

Si le même nom de méthode existe dans la classe elle-même, dans un trait qu'elle utilise et dans sa classe parente, PHP choisit dans cet ordre : la méthode propre de la classe, puis celle du trait, puis celle du parent. Dans le trait, parent:: atteint toujours la version du parent :

Un trait n'est pas un type

instanceof ne correspond jamais à un trait, et un paramètre typé avec un nom de trait rejette tout objet avec une TypeError. Pour demander « cette classe a-t-elle ce comportement », associez le trait à une interface, ou inspectez la classe avec class_uses() :

Le modèle ci-dessus est le modèle habituel : l'interface Exportable est ce que les fonctions utilisent comme type et ce que vérifie instanceof, et le trait ExportsProperties est une implémentation toute prête que les classes peuvent utiliser ou remplacer. Un trait seul est du code partagé sans contrat ; quand vous vous surprenez à vérifier class_uses() dans la logique métier, le trait réclamait une interface à côté de lui. Pour du code partagé par une famille de classes liées, une classe abstraite peut être le choix le plus simple.

Questions fréquentes

Qu'est-ce qu'un trait en PHP ?

Un trait est un groupe nommé de méthodes (et de propriétés) déclaré avec trait Name { } qu'une classe importe avec use Name;. PHP copie les membres du trait dans la classe, qui se comportent comme si vous les y aviez écrits. C'est une façon de partager du code entre des classes qui n'ont pas de parent commun.

Une classe PHP peut-elle utiliser plusieurs traits ?

Oui : use Timestamps, SoftDeletes; ou plusieurs lignes use. Si deux traits définissent une méthode du même nom, vous devez en choisir une avec insteadof, par exemple use A, B { A::hello insteadof B; }, et vous pouvez garder l'autre sous un nouveau nom avec B::hello as helloB;.

Quelle est la différence entre un trait et une interface en PHP ?

Une interface est un type sans code : elle dit quelles méthodes une classe doit avoir, et instanceof fonctionne avec elle. Un trait est du code sans type : il colle des corps de méthodes dans une classe, mais $obj instanceof SomeTrait est toujours faux. On les combine souvent : une interface pour le type, un trait avec une implémentation par défaut.

Un trait peut-il avoir un constructeur ou des méthodes abstraites ?

Oui pour les deux. Un trait peut déclarer abstract public function name(): string; pour exiger que la classe qui l'utilise fournisse cette méthode, et il peut définir __construct, même si un constructeur dans un trait entre facilement en conflit avec celui de la classe et est rarement une bonne idée.

Quelle méthode l'emporte si une classe et un trait définissent la même méthode ?

La méthode propre de la classe l'emporte sur celle du trait, et la méthode du trait l'emporte sur une méthode héritée de la classe parente. L'ordre est donc : classe, puis trait, puis parent.

Illustration des langages de programmation de Coddy

Apprendre à coder avec Coddy

COMMENCER