An trait is a mechanism for reusing methods and properties across classes without creating an inheritance hierarchy.
So far we’ve seen Inheritance (extends). It’s a Vertical relationship: Grandpa passes things to Dad, and Dad passes them to Son.
But what happens when you want to share code between classes that are not family?
Imagine you have a User class and an Order class. They have nothing to do with each other (a User is a person, an Order is a document).
However, you want both to have a system for generating a unique ID (UUID).
- Do you create a parent class
IDGeneratorand make them inherit from it? Wrong.Useralready inherits fromPerson. PHP won’t let you have two parents. - Do you copy and paste the code into both files? Wrong. You violate the DRY principle.
Traits were born for this. They are a Horizontal reuse mechanism.
What is a trait?
Think of a Trait as a “copyable” block of code. It’s a piece of a class that you can inject into any other class, regardless of its hierarchy.
You can think of PHP composing the trait’s members within the class. No separate instance of the trait is created.
Basic syntax
We define the trait with the trait keyword and use it inside the class with use.
trait Identifiable {
public function generateId(): string {
return uniqid('ID_');
}
}
class User {
use Identifiable; // Code injection!
public string $name;
}
class Product {
use Identifiable; // Reuse!
public float $price;
}
// Testing
$user = new User();
echo $user->generateId(); // Output: ID_65a4...
$prod = new Product();
echo $prod->generateId(); // Output: ID_65a4...Notice: User and Product are not family, but they both share the Identifiable capability.
Precedence order (who’s in charge?)
If I have a method in the Parent, another in the Trait, and another in the Class… which one gets executed?
Here’s the hierarchy:
The current class: If you write the method in the class, it overrides everything.
The trait: If the class doesn’t have it, the Trait’s method is used.
The parent class: It’s the last resort.
Trait > Inheritance. The Trait “overwrites” anything coming from extends.
class Base {
public function greet() { echo "Hello from Base"; }
}
trait GreetingTrait {
public function greet() { echo "Hello from Trait"; }
}
class Child extends Base {
use GreetingTrait;
// If I don't write anything here, the Trait wins.
}
$obj = new Child();
$obj->greet(); // Output: "Hello from Trait"Multiple traits and conflicts
A class can use as many traits as it wants.
class SuperClass {
use Loggable, Identifiable, Authenticatable;
}uniqid() works for this example, but it does not generate unpredictable identifiers. For security tokens or values, use random_bytes() or another cryptographically secure API.
If two traits have a method with the same name, PHP will throw a fatal error. You must resolve the conflict using insteadof or as (alias). Whenever possible, use specific names and design traits to reduce these collisions.
Modern traits (PHP 8.2+)
Traits have evolved. Today they are almost as powerful as classes.
Constants in traits
Since PHP 8.2, you can define constants inside a trait.
trait Configuration {
public const VERSION = '1.0';
}
class App {
use Configuration;
}
echo App::VERSION;Abstract methods in traits
You can force the class using the trait to implement a method.
trait Publishable {
// The class that uses me MUST have this method
abstract public function getContent(): string;
public function publish(): void {
echo "Publishing: " . $this->getContent();
}
}This is great for creating “mixins” that add functionality but depend on data from the host class.
When NOT to use traits
Traits are very powerful, but dangerous. They are called “GOTO on steroids” because they make the code hard to follow. If you open a class and see use A, B, C, D, E..., you have no idea what methods that class has or where they come from.
Best Practices:
- Use Traits for cross-cutting concerns (Logging, Caching, IDs).
- Don’t use Traits to simulate complex business logic multiple inheritance.
- If a Trait is huge, it should probably be a Class or an injected Service.