| by Đạt Trần | No comments

Understanding Traits In PHP

Trait is something a class has. A trait doesn’t define a type of a class. For example, Teacher is a type. Talk a lot is a trait. A teacher can either talk a lot or not.

trait TalkALot
{
    public function talk()
    {
        echo "I talk a lot";
    }
}

class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }
    use TalkALot;
}


$teacher = new Teacher("Oma");

$teacher->talk();

The code above will output “I talk a lot”

One class can implement multiple traits. However, those traits must not have same function name.

trait TalkALot
{
    public function talk()
    {
        echo "I talk a lot";
            }
}


trait TalkALittle
{
    public funtion talk(){
        echo "I don't talk";
    }

}

class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }
    use TalkALot, TalkALittle;
}


$teacher = new Teacher("Oma");

$teacher->talk();

The code above will cause an error:

Fatal error: Trait method talk has not been applied, because there are collisions with other trait methods on Teacher in C:\xampp\htdocs\lab\oop\index.php on line 21

You can use the keyword insteadof as a workaround in case your traits have same method name:

trait TalkALot
{

    public function talk()
    {
        echo $this->name . " talk all days";
    }
}

trait TalkALittle
{

    public function talk()
    {
        echo $this->name . " talk a little";
    }
}



class Teacher
{
    private $name;

    use TalkALot, TalkALittle {
    TalkALittle::talk insteadof TalkALot;
    }
    public function __construct($name)
    {
        $this->name = $name;
    }
}


$teacher = new Teacher("Oma");

$teacher->talk();

What if you want to use the other method that get overridden?

 trait TalkALot
{

    public function talk()
    {
        echo $this->name . " talk all days";
    }
}

trait TalkALittle
{

    public function talk()
    {
        echo $this->name . " talk a little";
    }
}



class Teacher
{
    private $name;

    use TalkALot, TalkALittle {
    TalkALot::talk insteadof TalkALittle;
    TalkALittle::talk as modestTalk;
    }
    public function __construct($name)
    {
        $this->name = $name;
    }
}


$teacher = new Teacher("Oma");

$teacher->modestTalk();

Here, I’ve defined an alias for the talk method of TalkALittle trait. Then, I can call the talk method in TalkALittle trait as modestTalk.

Trait can have private function, just like class.

Since trait is something a class has, it has access to all class’s variable and methods

trait TalkALot
{
    public function talk()
    {
        $this->requestSayName();
    }
}



class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function requestSayName()
    {
        echo "Say my name!";
    }
    use TalkALot;
}


$teacher = new Teacher("Oma");

$teacher->talk();

As you can see, the function talk is in the trait TalkALot. The $teacher instance call it. The talk function call the function requestSayname, which is defined in the Teacher class.

You cannot define a property in a trait then define a property with the same name in the class

The following code generates an error:

trait TalkALot
{
    private $name = "Trait";
    public function talk()
    {
        $this->requestSayName();
    }

    public function sayName()
    {
        echo $this->name;
    }
}



class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function requestSayName()
    {
        echo "Say my name!";
    }
    use TalkALot;
}


$teacher = new Teacher("Oma");

$teacher->sayName();
Fatal error: Teacher and TalkALot define the same property ($name) in the composition of Teacher. However, the definition differs and is considered incompatible. Class was composed in C:\xampp\htdocs\lab\oop\index.php on line 20

Trait can have static method. Static method in trait can access via the classes that use it either by class name or an instance:

trait TalkALot
{

    public function talk()
    {
        echo $this->name . " talk all days";
    }

    public static function tryTalking()
    {
        echo "bla bla <br />";
    }
}

trait TalkALittle
{

    public function talk()
    {
        echo $this->name . " talk a little";
    }
}



class Teacher
{
    private $name;

    use TalkALot, TalkALittle {
    TalkALot::talk insteadof TalkALittle;
    TalkALittle::talk as modestTalk;
    }
    public function __construct($name)
    {
        $this->name = $name;
    }
}


$teacher = new Teacher("Oma");


Teacher::tryTalking();
$teacher::tryTalking();

The above code prints two lines say “bla bla”

Leave a Reply