W3docs

trait

Learn the PHP trait keyword: define reusable methods, combine multiple traits, resolve conflicts with insteadof and as, and compare traits to interfaces.

The PHP "trait" Keyword: A Comprehensive Guide

A trait is a mechanism for reusing methods across independent classes. PHP uses single inheritance — a class can extend only one parent — so traits exist to solve the problem inheritance can't: sharing the same behaviour among classes that don't, and shouldn't, share a common ancestor. This is called horizontal code reuse.

A trait looks like a class, but you can't instantiate it on its own. Instead, you use it inside a class, and its methods and properties are copied in at compile time as if you had written them directly in that class.

This page covers how to define and use traits, how to combine several of them, how to resolve method-name conflicts, and how traits differ from inheritance and interfaces.

Traits are a class-level OOP feature. If you're new to PHP objects, start with Classes and Objects first.

Syntax

The basic syntax for defining a trait in PHP is as follows:

The PHP syntax of trait keyword

trait MyTrait {
  // Trait code here
}

In this example, we define a trait named "MyTrait" and include the trait code within the curly braces.

Usage

Traits can be incorporated into classes using the "use" keyword. Here's an example:

Example of PHP trait keyword

<?php

trait MyTrait
{
  public function sayHello()
  {
    echo "Hello from MyTrait!";
  }
}

class MyClass
{
  use MyTrait; // Incorporates trait methods into the class
}

$obj = new MyClass();
$obj->sayHello(); // Outputs: Hello from MyTrait!

This example defines a trait with a sayHello() method. The MyClass class incorporates the trait via the use keyword. Instantiating the class and calling the method outputs the trait's message.

Multiple Traits

It's also possible to incorporate multiple traits into a single class. Here's an example:

How to use trait keyword in PHP?

<?php

trait TraitA
{
  public function methodA()
  {
    echo "Method A";
  }
}

trait TraitB
{
  public function methodB()
  {
    echo "Method B";
  }
}

class MyClass
{
  use TraitA, TraitB; // Incorporates both traits
}

$obj = new MyClass();
$obj->methodA(); // Outputs: Method A
$obj->methodB(); // Outputs: Method B

Here, two traits are defined. MyClass incorporates both using a comma-separated list in the use statement. Calling the methods on an instance outputs their respective messages.

Conflict Resolution

When multiple traits define methods with the same name, PHP throws a fatal error. You must resolve conflicts using the insteadof and as operators.

Resolving trait conflicts

<?php

trait TraitA {
  public function hello() {
    echo "Hello from TraitA";
  }
}

trait TraitB {
  public function hello() {
    echo "Hello from TraitB";
  }
}

class MyClass {
  use TraitA, TraitB {
    TraitA::hello insteadof TraitB; // Resolves method name collision
    TraitB::hello as helloFromB;    // Creates an alias for the overridden method
  }
}

$obj = new MyClass();
$obj->hello();        // Outputs: Hello from TraitA
$obj->helloFromB();   // Outputs: Hello from TraitB

In this example, TraitA::hello replaces TraitB::hello for the class. The as operator creates an alias (helloFromB) so the original TraitB method remains accessible. This prevents fatal errors and gives you full control over method precedence.

The as operator can also change a method's visibility, for example TraitB::hello as protected; makes the imported method protected inside the class.

Abstract Methods in Traits

A trait can declare an abstract method to require that any class using it provides a specific implementation. This lets the trait call methods it doesn't define itself — a lightweight way to enforce a contract on the host class.

Requiring a method from the host class

<?php

trait Greetable
{
  abstract public function getName(): string;

  public function greet(): string
  {
    return "Hi, I'm " . $this->getName();
  }
}

class User
{
  use Greetable;

  public function __construct(private string $name) {}

  public function getName(): string
  {
    return $this->name;
  }
}

$user = new User("Ada");
echo $user->greet(); // Outputs: Hi, I'm Ada

Here greet() uses $this->getName(), but the trait leaves getName() abstract. The User class must implement it, or PHP raises a fatal error at compile time. Inside trait methods, $this always refers to the object of the class that uses the trait — traits have full access to that object's properties and methods.

Static Members in Traits

Traits can also contain static properties and methods. A key detail: each class that uses the trait gets its own independent copy of any static property — the value is not shared between different classes.

A static counter shared by all instances of one class

<?php

trait Counter
{
  public static int $count = 0;

  public function increment(): void
  {
    self::$count++;
  }
}

class Widget
{
  use Counter;
}

$a = new Widget();
$b = new Widget();
$a->increment();
$b->increment();

echo Widget::$count; // Outputs: 2

Both instances of Widget share the same Widget::$count, so the total is 2. If another class also used Counter, it would track its own separate count. For dedicated coverage, see Static Properties.

Traits vs. Interfaces vs. Inheritance

These three OOP tools are easy to confuse. Use this comparison to choose the right one:

FeatureProvides implementation?How many per class?Best for
TraitYes (concrete methods + properties)ManySharing the same code among unrelated classes
InterfaceNo (method signatures only)ManyDeclaring a contract a class must fulfil
InheritanceYesOne parentAn "is-a" relationship in a class hierarchy

A common, robust pattern is to pair them: declare an interface for the public contract, then provide a trait with the default implementation. Classes implement the interface and use the trait so they don't have to repeat the boilerplate. Traits do not appear in instanceof checks, which is exactly why you add an interface when you need type-based checks. If you instead need abstract base classes, reach for inheritance.

Benefits

Using traits in PHP has several benefits, including:

  • Code reuse: Traits provide a way to share code between classes without needing to create a new class hierarchy.
  • Improved organization: Traits allow developers to organize their code in a more modular way, making it easier to maintain and update.
  • Increased flexibility: Traits can be incorporated into multiple classes, providing a way to reuse code across multiple projects.

When to Use Traits (and When Not To)

Reach for a trait when several classes need the exact same concrete behaviour but don't belong in one inheritance chain — for example a Loggable trait giving a log() method to a Controller, a PaymentGateway, and a Job. Keep traits focused on a single responsibility.

Be cautious in a few cases:

  • Shared mutable state. A public static property in a trait becomes effectively global per class; prefer instance properties unless you genuinely want shared state.
  • Hidden coupling. Because traits are copied in at compile time, a method defined directly in the class always wins over the trait's version, which can silently override trait behaviour. Method resolution order is: current class → trait → parent class.
  • Overuse. If many traits start depending on each other, that's a sign the logic wants its own class (composition) instead.

Conclusion

The trait keyword lets you share concrete methods and properties across unrelated classes, working around PHP's single-inheritance limit. Combine multiple traits with a comma-separated use, resolve name clashes with insteadof and as, declare abstract methods to enforce a contract, and pair traits with interfaces when you also need type checks. Used deliberately, traits keep your code DRY and well organised.

Practice

Practice
What is the role of 'traits' in PHP?
What is the role of 'traits' in PHP?
Was this page helpful?