What are PHP Traits and how to use

What are PHP Traits and how to define them?

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 knowWhat 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.