In the following code you can see there are three classes, and they have a common method called sayHi()
, and all the sayHi()
methods are doing the same job for all the classes.
<?php
// Class 1
class MyClass1{
public function sayHi($name){
echo "Hi $name";
}
private function test(){
return false;
}
}
// Class 2
class MyClass2{
public function sayHi($name){
echo "Hi $name";
}
}
//Class 3
class MyClass3{
public function sayHi($name){
echo "Hi $name";
}
protected function add($a,$b){
return $a+$b;
}
}
Now the problem with the above code is the length of the code, and when you want to make the same changes in all three sayHi()
methods, you have to do in three places.
So how to reduce and make the code efficient? Here we will use PHP Traits.
What are the PHP Traits?
A PHP trait is a collection of user-defined methods and properties that you can reuse in a class.
How to define and use a PHP Trait?
You can define a Trait just like you define a class, you have to use the trait
keyword instead of the class
keyword. But, you cannot create objects of a trait.
The use
keyword is used to access a Trat’s methods and properties inside a class.
Syntax:
trait TraitName{
// Methods & properties
}
class MyClass{
// Using the trait
use TraitName;
}
Example:
<?php
trait MyTrait{
public function sayHi($name){
echo "Hi $name\n";
}
}
class MyClass1{
use MyTrait;
private function test(){
return false;
}
}
class MyClass2{
use MyTrait;
}
class MyClass3{
use MyTrait;
protected function add($a,$b){
return $a+$b;
}
}
$obj1 = new MyClass1();
$obj2 = new MyClass2();
$obj3 = new MyClass3();
$obj1->sayHi("Shyam");
$obj2->sayHi("Raju");
$obj3->sayHi("Baburao");
Hi Shyam
Hi Raju
Hi Baburao
Multiple traits in a class
Yes, you can implement multiple traits inside a class. You have to separate the traits with a comma.
Syntax:
trait MyTrait{
...
}
trait MyTrait2{
...
}
class MyClass{
use MyTrait, MyTrait2;
}
Trait method overriding
Do you know – What is Method Overriding?
What if we create a method within a class with the same name that already exists in the trait that the class using?
Look at the following code – The SayHi()
method is present in MyTrait
as well as MyClass
.
The SayHi()
method of the MyClass
will run because its priority is higher than the trait’s method.
<?php
trait MyTrait{
public function sayHi(){
echo "Hi from Trait.";
}
}
class MyClass{
use MyTrait;
public function sayHi(){
echo "Hi from MyClass.";
}
}
$obj = new MyClass();
$obj->sayHi();
Hi from MyClass.
What if the parent class also has a method with the same name?
Class’s own methods always have high priority, then the trait’s methods, and finally the parent class’s methods.
<?php
trait MyTrait{
public function sayHi(){
echo "Hi from Trait.";
}
}
class ParentClass{
public function sayHi(){
echo "Hi from Parent Class.";
}
}
class MyClass extends ParentClass{
use MyTrait;
}
$obj = new MyClass();
$obj->sayHi();
Hi from Trait.
What if multiple traits have a method with the same name?
Now what if multiple traits have a method with the same name and you are using those traits in a class?
In this case, you will get a Fatal error.
<?php
trait trait1{
public function sayHi(){
echo "Hi from Trait 1.";
}
}
trait trait2{
public function sayHi(){
echo "Hi from Trait 2.";
}
}
class MyClass{
use trait1, trait2;
}
$obj = new MyClass();
$obj->sayHi();
How to resolve the above problem?
You have to define whose method you want to use trait1
‘s method or trait2
‘s method.
So If we want to use the trait1
‘s sayHi()
method instead of the trait2
‘s sayHi()
method, then our syntax will be –
class MyClass{
use trait1, trait2{
trait1:: sayHi insteadof trait2;
}
}
<?php
trait trait1{
public function sayHi(){
echo "Hi from Trait 1.";
}
}
trait trait2{
public function sayHi(){
echo "Hi from Trait 2.";
}
}
class MyClass{
use trait1, trait2{
trait1:: sayHi insteadof trait2;
}
}
$obj = new MyClass();
$obj->sayHi();
Hi from Trait 1.
But suppose you are a stubborn person and you want to use the SayHi()
methods of both trait1
and trait2
.
Yes, you can do that, but you have to rename the sayHi()
method of one of the traits
.
You can rename by using the as
keyword –
class MyClass{
use trait1, trait2{
trait1:: sayHi insteadof trait2;
trait2:: sayHi as hello;
}
}
<?php
trait trait1{
public function sayHi(){
echo "Hi from Trait 1.\n";
}
}
trait trait2{
public function sayHi(){
echo "Hi from Trait 2.";
}
}
class MyClass{
use trait1, trait2{
trait1:: sayHi insteadof trait2;
trait2:: sayHi as hello;
}
}
$obj = new MyClass();
$obj->sayHi();
$obj->hello();
Hi from Trait 1.
Hi from Trait 2.
Changing the access modifier
The as
keyword is also used to change access modifiers of trait methods.
<?php
trait trait2{
protected function sayHello(){
echo "Hi from Trait 2.";
}
}
class MyClass{
use trait2{
trait2:: sayHello as public;
}
}
$obj = new MyClass();
$obj->sayHello();
Hi from Trait 2.
Combination of renaming and changing access modifiers
<?php
trait trait2{
protected function sayHello(){
echo "Hi from Trait 2.";
}
}
class MyClass{
use trait2{
trait2:: sayHello as public abc;
}
}
$obj = new MyClass();
$obj->abc();
Hi from Trait 2.