PHP trait
We know that extending from classes allows us to inherit code (properties and method implementations), but it has the limitation of extending only from one class each time. So, what do we do if two unrelated PHP classes need to exhibit similar behavior? To solve the problem of single inheritance, PHP 5.4 introduced a feature called traits:
- A trait contains a set of methods and properties just like a class, but cannot be instantiated by itself.
- Instead, the trait is included into a class and the class can then use its methods and properties as if they were declared in the class itself.
- A class may use multiple traits by placing them in a comma-separated list. Similarly, a trait may be composed of one or more other traits.
The structure of a trait is the same as a class, except that it’s declared using the keyword trait
instead of class. It is considered good practice to define only one trait per file, just like class and interface definitions:
<?php trait Users { //... }
Example: Creating a Users
trait:
<?php trait Users { protected $firstName; protected $lastName; public function setFirstName($fn) { $this->firstName = $fn; } public function setLastName($ln) { $this->lastName = $ln; } public function getName() { return $this->firstName . $this->lastName; } }
PHP use
a Trait
Using a PHP trait is easy. We import traits into a class with the use
keyword (both namespaces and traits are imported with the use
keyword). To use the Users
trait, add the code use Users
inside some PHP classes definition. Here’s an example:
<?php class BrainBellLibrary { use Users; // class code } class AnotherClass { use Users; } $x = new BrainBellLibrary(); $x->setFirstName ('Brain'); $x->setLastName ('Bell'); echo $x->getName(); //Prints BrainBell $n = new AnotherClass(); $n->setFirstName ('Abc'); $n->setLastName ('Xyz'); echo $n->getName(); //Prints AbcXyz
The trait’s methods behave as if they were directly defined in that class.
Inheritance and Traits
Trait methods override inherited methods. Likewise, methods defined in the class override methods inserted by a trait.
<?php trait MyTrait { public function sayHello() { echo 'Trait says hello'; } } class MyParent { public function sayHello() { echo 'MyParent class says hello'; } } class MyClass extends MyParent { use MyTrait; } class MySecClass extends MyParent { use MyTrait; public function sayHello() { echo 'The child class says hello'; } } $a = new MyClass(); $a->sayHello(); //Override the MyParent //Prints: Trait says hello $b = new MySecClass(); $b->sayHello(); //Override the MyTrait and MyParent //Prints: The child class says hello
PHP trait conflicts
PHP will generate a fatal error if two traits attempt to insert a method with the same name:
Example: Using traits having the same name methods
<?php trait Users { protected $uname; public function setName($n){ $this->uname = $n; } } trait Books { protected $bname; public function setName($n){ $this->bname = $n; } } //Use both traits class MyClass { use Books, Users; }
When you execute the above code, it generates the following error:
Fatal error: Trait method Users::setName
has not been applied as MyClass::setName
, because of collision with Books::setName
in…
Excluding trait methods
Using insteadof
keyword to choose a method between traits to resolve conflict
To resolve the conflict you can use the insteadof
keyword to specify which of the conflicting methods you want to use. In the following example, we choose Users trait’s method:
<?php class MyClass { use Books, Users { Users::setName insteadof Books; } } $myclass = new MyClass(); $myclass->setName('My username');
Aliasing trait methods
Using as
keyword to keep conflicting methods between traits.
The above code lets you exclude one of the trait methods, but if you want to keep both methods, you also need to use the as
keyword:
<?php class MyClass { use Users,Books { Books::setName insteadof Users; Users::setName as setUsername; } } $myclass = new MyClass(); $myclass->setName('My Book Name'); $myclass->setUsername('My username');
First, use the insteadof
keyword to exclude the conflicting method, and then use the as
keyword to include that method with a different name to reference it, this way you can use the conflicting methods.
PHP OOP Tutorials: