@daniloparrajr

PHP Traits

  • 7/16/2024
  • 3 min read

Introduction

PHP Traits intended use is to reduce code duplication and increase code reuse. If you have the same methods across classes then it is best to traits. To understand PHP Traits much easier, think of it as “copy and paste” where the traits code are inserted to the implementing class at compile time.

Use the trait keyword to create a trait, and use the use keyword within the class to insert the trait.

trait LatteTrait {
public function makeLatte() {
echo __CLASS__ . '';
}
}
class LatteMaker {
use LatteTrait;
}

Method precedence

Overriding Trait Methods

Developers can override any trait methods by creating the same method name within the class.

trait LatteTrait {
public function makeLatte(): string {
return __CLASS__ . PHP_EOL;
}
public function anotherTraitMethod(): string {
return __CLASS__ . PHP_EOL;
}
}
class LatteMarker {
use LatteTrait;
// Override the makeLatte method in LatteTrait!
public function makeLatte() {
echo 'From LatterMaker class!' . PHP_EOL;
}
}
$LatteMaker = new LatteMarker();
echo $LatteMaker->makeLatte(); // From LatterMaker class!

Overriding Parent Class Using Trait Methods In Child Class

Trait methods will override any methods of the base class if the child class use it.

trait LatteTrait {
public function makeLatte(): string {
return __CLASS__ . PHP_EOL;
}
}
class LatteMarker {
public function makeLatte(): string {
return 'From the Latter Marker class!';
}
}
// Child class using traits to override parent method.
class LatteMarkerChild extends LatteMarker {
use LatteTrait;
}
$LatteMakerChild = new LatteMarkerChild();
echo $LatteMakerChild->makeLatte(); // LatteMarkerChild

Conflicting method names and properties

When implementing multiple traits, same name methods will cause a conflict. There are two ways to get around this using the insteadof operator and as operator.

insteadof operator

The insteadof operator lets you specify which method to run when there is a conflict between the method names.

trait LatteTrait {
public function makeCoffee() {
echo __CLASS__ . 'is making coffee' . PHP_EOL;
}
}
trait CappuccinoTrait{
public function makeCoffee() {
echo __CLASS__ . 'is making coffee' . PHP_EOL;
}
}
// This will produce an error because both traits have the same makeCofee method.
class CoffeeMaker{
use CappuccinoTrait;
// Use insteadof keyword to prevent conflicting method names.
use LatteTrait {
// use LatteTrait makeCoffee method instead of CappuccinoTrait.
LatteTrait::makeCoffee insteadof CappuccinoTrait;
};
}

as operator

The as operator lets use alias the method to a different name.

trait LatteTrait {
public function makeCoffee() {
echo __CLASS__ . 'is making coffee' . PHP_EOL;
}
}
trait CappuccinoTrait{
public function makeCoffee() {
echo __CLASS__ . 'is making coffee' . PHP_EOL;
}
}
// This will produce an error because both traits have the same makeCofee method.
class CoffeeMaker{
use CappuccinoTrait;
// Use alias keyword to prevent conflicting method names.
use LatteTrait{
// rename the makeCofee method to makeOriginalCoffee to prevent name conflict.
LatteTrait::makeCoffee as makeOriginalCoffee;
};
}

Composing traits within other traits

Developers can also use traits within traits.

trait LatteTrait {
public function makeLatte() {
echo __CLASS__ . 'is making latte' . PHP_EOL;
}
}
trait CappuccinoTrait {
use LatteTrait;
public function makeCappuccino() {
echo __CLASS__ . 'is making cappuccino' . PHP_EOL;
}
}
class CoffeeMaker {
use CappuccinoTrait;
// use LatteTrait;
}

Properties within Traits

The recommended way of addressing properties within traits is by having a setter method within the trait.

trait LatteTrait {
private string $milkType = 'whole-milk';
public function makeLatte() {
echo __CLASS__ . 'is making latte using ' . $this->milkType . PHP_EOL ;
}
public function setMilkType(string $milkType): static {
$this->milkType = $milkType;
return $this;
}
}
class CoffeeMaker {
use LatteTrait ;
}

Static properties and methods within traits

Traits can also have static properties, static methods and static variables. Unlike inheritance static properties are independent to the class that implements the trait. Unlike inheritance where static properties are shared.

Comparing Inheritance & traits

Traits are best used if you want to share a method where inheritance is not applicable (is-a relationship).

Related Articles