Traits

Reviewed & published by Brayan K

PHP classes can only inherit from one parent — but real apps often need the same behaviour (logging, timestamps, slugs) across unrelated classes. Traits are PHP's answer: reusable bundles of methods you mix into any class, no shared parent required.

Part of the free PHP course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Your First Trait

Declare a trait just like a class, but with the trait keyword. Inside it lives one or more methods. To use it, write use TraitName; at the top of a class body — PHP effectively copies the trait's methods into that class. Two completely unrelated classes can both use the same trait and gain the behaviour.

<?php
// A TRAIT is a reusable bundle of methods you can mix INTO any class.
// It solves a real problem: PHP has no multiple inheritance, but two
// unrelated classes often need the SAME behaviour.

trait Loggable {
    public function log(string $message): void {
        echo '[' . static::class . '] ' . $message . "\n";
    }
}

// "use" pulls the trait's methods into the class, as if copy-pasted.
class Order {
    use Loggable;
}
class Invoice {
    use Loggable;
}

(new Order())->log('created');     // [Order] created
(new Invoice())->log('paid');      // [Invoice] paid
?>

2️⃣ Traits With State

Traits aren't limited to methods — they can declare properties too, and even abstract methods. When the trait is mixed in, those properties become part of the class. Inside the trait, $this refers to whatever object is using it, so the trait can read and write the host's state.

<?php
// Traits can hold PROPERTIES and abstract methods too — not just concrete code.
trait HasTimestamps {
    private ?string $createdAt = null;

    public function touch(): void {
        $this->createdAt = '2026-06-18';
    }

    public function getCreatedAt(): ?string {
        return $this->createdAt;
    }
}

class Article {
    use HasTimestamps;

    public function __construct(public string $title) {}
}

$a = new Article('Hello Traits');
echo $a->getCreatedAt() ?? 'not set';   // not set
echo "\n";
$a->touch();
echo $a->getCreatedAt();                 // 2026-06-18
?>

3️⃣ Composing Multiple Traits

A single class can use several traits at once, separated by commas (or in separate use lines). This is the real power: you build a class up from small, focused, reusable behaviours instead of one giant inheritance tree.

<?php
// A class can use SEVERAL traits at once — compose behaviour like Lego.
trait Greetable {
    public function greet(): string { return "Hi, I'm " . $this->name; }
}
trait Farewell {
    public function bye(): string { return "Bye from " . $this->name; }
}

class Person {
    public function __construct(public string $name) {}
    use Greetable, Farewell;
}

$p = new Person('Ada');
echo $p->greet() . "\n";   // Hi, I'm Ada
echo $p->bye()   . "\n";   // Bye from Ada
?>

4️⃣ Resolving Conflicts

What if two traits both define a method called log()? PHP won't guess — it raises a fatal error and asks you to choose. Inside the use block, A::method insteadof B picks the winner, and B::method as alias keeps the other version available under a new name.

<?php
// If two traits define the SAME method name, PHP raises a conflict.
// You resolve it explicitly with insteadof and (optionally) as.
trait FileLogger {
    public function log(): string { return 'to file'; }
}
trait DbLogger {
    public function log(): string { return 'to database'; }
}

class Service {
    use FileLogger, DbLogger {
        // Use FileLogger::log() as the winning log()...
        FileLogger::log insteadof DbLogger;
        // ...but keep the other under an alias.
        DbLogger::log as logToDb;
    }
}

$s = new Service();
echo $s->log()     . "\n";   // to file
echo $s->logToDb() . "\n";   // to database
?>

Now you try — fill in each ___ using the 👉 hint, then run it and check against the Output panel.

<?php
// 🎯 YOUR TURN — fill in each blank marked ___ , then run it.

trait Sluggable {
    public function slug(): string {
        return strtolower(str_replace(' ', '-', $this->title));
    }
}

class Post {
    public function __construct(public string $title) {}
    ___ Sluggable;          // 👉 the keyword that mixes a trait into a class
}

$p = new Post('Hello World');
echo $p->___() . "\n";     // 👉 the method the trait provides
                            // should print: hello-world

// ✅ Expected output:
//    hello-world
?>

🧩 Reorder Challenge

These lines define a trait, mix it into a class, and call its method — but they're scrambled. Put them in the order PHP needs.

C → B → E → A → D

The trait must be declared first: open it (C), define its method (B), close it (E). Only then can a class mix it in (A) and call the method (D), which prints pong.

🧠 Quick Recall — Predict the Output

hihi — both unrelated classes gained the same hi() method from the trait, with no shared parent.

2. Does each object keep its own state?

21 — the trait's property belongs to each instance, so $a reaches 2 and $b reaches 1 independently.

3. What happens here?

A fatal error — both traits define go(), an unresolved conflict. You must add an insteadof rule in the use block to choose a winner.

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Traits

SyntaxExampleWhat It Does
trait X {}trait Loggable { ... }Declare a trait
use X;class Order { use Loggable; }Mix a trait into a class
use A, B;use Greetable, Farewell;Mix in several traits
A::m insteadof B;FileLogger::log insteadof DbLogger;Resolve a method conflict
B::m as alias;DbLogger::log as logToDb;Keep loser under a new name
abstract functionabstract public function name(): string;Require host to implement

Mini-Challenge: Reusable Counter Trait

No code is filled in this time — just a brief and an outline. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments.

<?php
// 🎯 MINI-CHALLENGE: a reusable "counter" trait.
// No code is filled in — work from the steps below, then run it.
//
// 1. Make a trait Countable2 with:
//       a private int $count = 0;
//       a method increment(): void that adds 1 to $count;
//       a method count(): int that returns $count.
// 2. Make TWO classes, Cart and Playlist, that each "use Countable2".
// 3. On a Cart, call increment() twice, then echo count()  -> 2
// 4. On a Playlist, call increment() once, then echo count() -> 1
//    (Each object must keep its OWN independent count.)
//
// ✅ Expected output:
//    2
//    1

// your code here
?>

🎉 Lesson Complete!

Practice quiz

Which keyword mixes a trait into a class?

  • extends
  • implements
  • use
  • import

Answer: use. Inside a class body you write 'use TraitName;' to mix the trait's methods in.

Why do traits exist in PHP?

  • To share behaviour across classes despite single inheritance
  • To replace interfaces entirely
  • To allow multiple inheritance of classes
  • To make classes abstract

Answer: To share behaviour across classes despite single inheritance. PHP has no multiple inheritance, so traits let unrelated classes share the same methods.

What happens if two traits used in one class define the same method name?

  • The last trait silently wins
  • PHP merges both method bodies
  • Nothing — both are kept under the same name
  • A fatal conflict error unless you resolve it

Answer: A fatal conflict error unless you resolve it. PHP refuses to guess; you must resolve it with insteadof (and optionally as) in the use block.

Which syntax resolves a method conflict between FileLogger and DbLogger?

  • FileLogger::log override DbLogger;
  • FileLogger::log insteadof DbLogger;
  • use FileLogger over DbLogger;
  • FileLogger::log replaces DbLogger;

Answer: FileLogger::log insteadof DbLogger;. insteadof picks the winning method; 'DbLogger::log as logToDb;' keeps the loser under a new name.

Can a trait declare properties, not just methods?

  • Yes — properties and even abstract methods
  • No — methods only
  • Only constants
  • Only static properties

Answer: Yes — properties and even abstract methods. Traits can hold properties and abstract methods; mixed-in properties become part of the host class.

Two unrelated classes A and B both 'use Hi' (returns 'hi'). What does (new A)->hi() . (new B)->hi() print?

  • hi
  • An error
  • hihi
  • AB

Answer: hihi. Both classes gained the same hi() method from the trait, with no shared parent.

Does a trait property belong to the class or each instance?

  • All instances share one value
  • Each instance keeps its own independent value
  • It is read-only
  • It is static by default

Answer: Each instance keeps its own independent value. A trait's property belongs to each instance, so two objects keep independent state.

What is the difference between a trait and an interface?

  • An interface carries code; a trait only declares signatures
  • They are identical
  • A trait can be instantiated but an interface cannot
  • A trait carries real method bodies; an interface only declares signatures

Answer: A trait carries real method bodies; an interface only declares signatures. An interface is a contract of signatures; a trait carries actual implementations copied into the class.

What happens if you try new SomeTrait()?

  • It creates an empty object
  • An error — traits cannot be instantiated
  • It returns null
  • It works like a class

Answer: An error — traits cannot be instantiated. Traits aren't classes; you mix them into a class with use and instantiate that class instead.

How can a trait force the host class to supply a method?

  • Use a private method
  • Throw an exception
  • Declare an abstract method in the trait
  • It cannot require anything

Answer: Declare an abstract method in the trait. An abstract method in a trait forces any class using it to implement that method.

Continue this course

Frequently asked questions

What's the difference between a trait and an interface in PHP?

An interface is a contract: it declares method signatures with no bodies, and a class that implements it promises to provide those methods. A trait is the opposite — it carries actual method implementations (and even properties) that get copied into the class. You reach for an interface to say 'this class can be treated as an X'; you reach for a trait to share working code across classes that can't share a common parent. They complement each other: a class often implements an interface and uses a trait that fulfils it.

Why use a trait instead of inheritance?

PHP only allows single inheritance — a class can extend exactly one parent. Traits sidestep that limit: a class can use as many traits as it likes, mixing in behaviour from several sources. They're ideal when unrelated classes need the same capability (logging, timestamps, slug generation) but don't share a meaningful is-a relationship. The rule of thumb: use inheritance for a true 'is-a' hierarchy, and a trait for a reusable 'has-this-behaviour' capability you want to bolt onto many classes.

What happens if two traits define a method with the same name?

You get a fatal conflict error unless you resolve it explicitly. Inside the use block you write A::method insteadof B; to pick which trait's version wins, and optionally B::method as otherName; to keep the loser available under a different name. This explicit resolution is intentional — PHP refuses to guess which implementation you meant, which prevents silent, hard-to-find bugs.

Can a trait have abstract methods or require properties from the class?

Yes. A trait can declare an abstract method, which forces any class using it to implement that method — a clean way to require the host class to supply a missing piece. Traits can also reference properties they expect to exist (like $this->name) or declare their own properties. This lets a trait define a 'template' of behaviour while delegating the specifics to whatever class mixes it in, similar in spirit to the template method pattern.

Related lessons