01 · THE IDEAREAD → TRY → LEARN
Why traits exist
PHP classes can extend only one parent. Sometimes two unrelated classes need the same small piece of behavior, such as a counter, a formatter or a helper method. Putting that code in a shared parent forces an inheritance relationship that may not make sense. A trait solves this: it groups methods and properties that a class can copy in with the use keyword. This is called horizontal composition, because the behavior is added without a parent-child relationship.
A trait looks like a class but is declared with trait. You cannot instantiate a trait on its own. It only becomes useful when a class uses it.
A first worked example
The trait below holds a private counter and a method that increments it. Two unrelated classes use it. Each object gets its own copy of the property, so the counters do not interfere.
trait Counts {
private int $count = 0;
public function increment(): int {
$this->count++;
return $this->count;
}
}
class Clicks {
use Counts;
}
class Downloads {
use Counts;
}
$clicks = new Clicks();
$downloads = new Downloads();
$clicks->increment();
echo json_encode([$clicks->increment(), $downloads->increment()]);
echo "\n";[2,1]
The Clicks object was incremented twice and the Downloads object once, so the result is [2,1]. Inside a trait method, $this refers to the object of the class that uses the trait.
Precedence
When the same method name exists in several places, PHP picks one by a fixed order: a method written in the current class wins over a trait method, and a trait method wins over an inherited method.
class Base {
public function who(): string {
return 'base';
}
}
trait Marks {
public function who(): string {
return 'trait';
}
}
class FromTrait extends Base {
use Marks;
}
class FromClass extends Base {
use Marks;
public function who(): string {
return 'class';
}
}
echo json_encode([(new Base())->who(), (new FromTrait())->who(), (new FromClass())->who()]);
echo "\n";["base","trait","class"]
The three results are base, trait and class. This lets a class customize a trait method by simply defining its own version.
Using several traits and resolving conflicts
A class can list several traits after use, separated by commas. If two of those traits provide a method with the same name, PHP raises a fatal error unless you resolve the conflict. Use insteadof to choose which trait wins, and as to give another version an additional name. The as operator adds an alias; it does not rename or remove anything.
trait A {
public function talk(): string {
return 'a';
}
}
trait B {
public function talk(): string {
return 'b';
}
}
class Talker {
use A, B {
B::talk insteadof A;
A::talk as talkA;
}
}
$t = new Talker();
echo json_encode([$t->talk(), $t->talkA()]);
echo "\n";["b","a"]
Here talk() comes from B, while the excluded A version is still reachable as talkA().
Other useful facts
- A trait can declare properties. If the using class declares the same property, it must be compatible (same visibility, type, readonly modifier and initial value), or PHP raises a fatal error.
- A trait can use other traits.
- A trait can declare an abstract method to require that the using class provides it.
- A static variable inside a trait method is separate for each class that uses the trait.
- Call static members on the class that uses the trait, not on the trait itself; direct access on a trait is deprecated.
Common mistakes
- Trying
newon a trait. Traits are not instantiable. - Using two traits with the same method name and forgetting
insteadof. - Using traits where a clear interface or a parent class would express the design better. Traits share code; they do not create a type you can check against.
Exercise contract
Write the function announceAll(array $messages): array. The starter already defines a trait Shouts with a shout() method and an empty Announcer class. Make Announcer use the trait, then return a list where each message has been passed through shout(), which trims the text, uppercases it and appends !. An empty input array returns an empty array, and an empty string becomes !.
Recap
A trait is a bundle of methods and properties copied into a class with use. The class wins over the trait, and the trait wins over the parent. Resolve duplicate names with insteadof and as.
Classes
- Define a reusable trait method
- Compose it into a class without inheritance