Traits

A class can extend only one parent, but sometimes unrelated classes need the same small piece of behaviour — timestamps, a slug generator, logging. A trait is a reusable bundle of methods and properties that's copied into any class that uses it. Laravel and other frameworks use traits heavily.

Defining and using a trait

PHP
<?php

trait HasTimestamps
{
    public ?string $createdAt = null;
    public ?string $updatedAt = null;

    public function touch(string $when): void
    {
        $this->createdAt ??= $when;
        $this->updatedAt = $when;
    }
}

class Post
{
    use HasTimestamps;

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

class Comment
{
    use HasTimestamps;
}

$post = new Post("Hello traits");
$post->touch("2026-10-01");
$post->touch("2026-10-08");
echo "{$post->title}: created {$post->createdAt}, updated {$post->updatedAt}\n";

$c = new Comment();
$c->touch("2026-10-05");
echo "Comment updated {$c->updatedAt}\n";
Output
Hello traits: created 2026-10-01, updated 2026-10-08
Comment updated 2026-10-05

Post and Comment share no parent class, yet both got the properties and the touch() method. Think of use inside a class as "paste these members here".

Traits can use the host class

Inside a trait, $this is the object of whatever class uses it. A trait can rely on members the class provides, and can declare abstract methods to make that requirement explicit:

PHP
<?php

trait Sluggable
{
    abstract public function sluggableText(): string;

    public function slug(): string
    {
        return trim(preg_replace('/[^a-z0-9]+/', '-', strtolower($this->sluggableText())), '-');
    }
}

class Article
{
    use Sluggable;

    public function __construct(private string $title) {}
    public function sluggableText(): string { return $this->title; }
}

class Category
{
    use Sluggable;

    public function __construct(private string $name) {}
    public function sluggableText(): string { return $this->name; }
}

echo new Article("Ten PHP Tips & Tricks!")->slug(), "\n";
echo new Category("Home & Garden")->slug(), "\n";
Output
ten-php-tips-tricks
home-garden

Several traits

A class can use several traits. If two traits define a method with the same name, you must decide which one wins with insteadof, and can keep the other under a new name with as:

PHP
<?php

trait Loggable
{
    public function describe(): string { return "loggable"; }
    public function log(string $msg): string { return "[log] $msg"; }
}

trait Exportable
{
    public function describe(): string { return "exportable"; }
    public function toCsv(array $row): string { return implode(",", $row); }
}

class Report
{
    use Loggable, Exportable {
        Exportable::describe insteadof Loggable;
        Loggable::describe as describeLogging;
    }
}

$r = new Report();
echo $r->describe(), " / ", $r->describeLogging(), "\n";
echo $r->log("generated"), " / ", $r->toCsv(["a", 1]), "\n";
Output
exportable / loggable
[log] generated / a,1

Static members and constants

Traits can have static properties and methods, and (since PHP 8.2) constants. Each class using the trait gets its own copy of a static property:

PHP
<?php

trait CountsInstances
{
    private static int $count = 0;

    public static function created(): int { return self::$count; }

    private function countInstance(): void { self::$count++; }
}

class Apple
{
    use CountsInstances;
    public function __construct() { $this->countInstance(); }
}

class Pear
{
    use CountsInstances;
    public function __construct() { $this->countInstance(); }
}

new Apple(); new Apple(); new Pear();
echo Apple::created(), " apples, ", Pear::created(), " pear\n";
Output
2 apples, 1 pear

Precedence

When names collide, methods defined in the class override the trait's, and the trait's override inherited ones:

PHP
<?php

class Base
{
    public function hello(): string { return "Base"; }
}

trait SaysHello
{
    public function hello(): string { return "Trait (overriding " . parent::hello() . ")"; }
}

class A extends Base { use SaysHello; }
class B extends Base
{
    use SaysHello;
    public function hello(): string { return "Class B"; }
}

echo new A()->hello(), "\n";
echo new B()->hello(), "\n";
Output
Trait (overriding Base)
Class B

When to use traits

Traits are a tool for sharing implementation, not for describing types: you can't type-hint a trait, and instanceof doesn't recognise one. Good uses are small, self-contained behaviours that many classes need. Pair them with an interface when callers need a type:

PHP
<?php

interface HasSlug
{
    public function slug(): string;
}

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

class Page implements HasSlug
{
    use SlugFromTitle;
    public function __construct(public string $title) {}
}

function linkTo(HasSlug $item): string
{
    return "/" . $item->slug();
}

echo linkTo(new Page("About Us")), "\n";
var_dump(class_uses(new Page("x")));
Output
/about-us
array(1) {
  ["SlugFromTitle"]=>
  string(13) "SlugFromTitle"
}

Be wary of large traits holding lots of state, or classes using many traits: the behaviour gets scattered, and it becomes hard to see what a class really does. Composition — giving a class an object that does the job — is often clearer.

Try it yourself

Write a HasDiscount trait that adds a discount percentage and a finalPrice() method to any class with a price property.

Try it yourself · main.php
Edit the code, copy it into main.php, then run it with php main.php (PHP 8.5). How to install PHP
Output
10.39
0