基礎

PHPのトレイト|useで複数クラスにコードを再利用する方法

PHPのトレイト(Trait)は、複数のクラスでコード(メソッドやプロパティ)を共有するための仕組みです。PHPは単一継承しかサポートしないため、継承では解決できないコードの再利用問題を、トレイトで解決できます。

trait で定義し、使いたいクラスで use キーワードで取り込みます。1つのクラスが複数のトレイトを使え、まるでコードを「コピー&ペースト」するように機能を追加できます。

基本的な使い方

PHP
<?php
trait Timestampable {
    private string $createdAt;
    private string $updatedAt;

    public function setCreatedAt(): void {
        $this->createdAt = date("Y-m-d H:i:s");
    }

    public function setUpdatedAt(): void {
        $this->updatedAt = date("Y-m-d H:i:s");
    }

    public function getTimestamps(): string {
        return "作成: {$this->createdAt}、更新: {$this->updatedAt}";
    }
}

class User {
    use Timestampable;

    public function __construct(public string $name) {
        $this->setCreatedAt();
        $this->setUpdatedAt();
    }
}

class Article {
    use Timestampable;

    public function __construct(public string $title) {
        $this->setCreatedAt();
        $this->setUpdatedAt();
    }
}

$user = new User("田中");
echo "ユーザー: {$user->name} - {$user->getTimestamps()}\n";

$article = new Article("PHP入門");
echo "記事: {$article->title} - {$article->getTimestamps()}\n";
実行結果
ユーザー: 田中 - 作成: 2026-02-19 10:00:00、更新: 2026-02-19 10:00:00
記事: PHP入門 - 作成: 2026-02-19 10:00:00、更新: 2026-02-19 10:00:00

Timestampable トレイトを UserArticle の両方で使っています。継承関係がないクラス間でも同じ機能を共有できます。

複数のトレイトを使う

PHP
<?php
trait HasName {
    private string $name;
    public function getName(): string { return $this->name; }
    public function setName(string $name): void { $this->name = $name; }
}

trait HasEmail {
    private string $email;
    public function getEmail(): string { return $this->email; }
    public function setEmail(string $email): void { $this->email = $email; }
}

trait Loggable {
    public function log(string $action): void {
        echo "[LOG] " . get_class($this) . ": {$action}\n";
    }
}

class Employee {
    use HasName, HasEmail, Loggable;

    public function __construct(string $name, string $email) {
        $this->setName($name);
        $this->setEmail($email);
        $this->log("新規作成");
    }

    public function show(): void {
        echo "{$this->getName()} ({$this->getEmail()})\n";
    }
}

$emp = new Employee("田中太郎", "tanaka@example.com");
$emp->show();
実行結果
[LOG] Employee: 新規作成
田中太郎 (tanaka@example.com)

メソッド名の衝突解決

複数のトレイトに同名のメソッドがある場合、insteadofas で衝突を解決します。

PHP
<?php
trait Japanese {
    public function greet(): string {
        return "こんにちは";
    }
}

trait English {
    public function greet(): string {
        return "Hello";
    }
}

class Bilingual {
    use Japanese, English {
        Japanese::greet insteadof English;  // Japaneseを優先
        English::greet as greetInEnglish;   // Englishは別名で使う
    }
}

$person = new Bilingual();
echo $person->greet() . "\n";
echo $person->greetInEnglish() . "\n";
実行結果
こんにちは
Hello

実用的な例

PHP
<?php
trait SoftDelete {
    private bool $deleted = false;
    private ?string $deletedAt = null;

    public function softDelete(): void {
        $this->deleted = true;
        $this->deletedAt = date("Y-m-d H:i:s");
    }

    public function restore(): void {
        $this->deleted = false;
        $this->deletedAt = null;
    }

    public function isDeleted(): bool {
        return $this->deleted;
    }
}

class Post {
    use SoftDelete;

    public function __construct(public string $title) {}

    public function getStatus(): string {
        $status = $this->isDeleted() ? "削除済み" : "公開中";
        return "{$this->title}({$status})";
    }
}

$post = new Post("PHPトレイト解説");
echo $post->getStatus() . "\n";

$post->softDelete();
echo $post->getStatus() . "\n";

$post->restore();
echo $post->getStatus() . "\n";
実行結果
PHPトレイト解説(公開中)
PHPトレイト解説(削除済み)
PHPトレイト解説(公開中)
ポイント

トレイトはLaravelなどのフレームワークで広く使われています。例えば、SoftDeletes(論理削除)、HasFactory(テストデータ生成)、Notifiable(通知送信)などがトレイトとして提供されています。

注意

トレイトを多用しすぎると、クラスの責務が不明確になりやすいです。「このクラスは何をするのか」が分かりにくくならないよう、1つのトレイトには1つの明確な責務を持たせましょう。

まとめ

  • trait でコードの断片を定義し、use でクラスに取り込める
  • 継承関係のない複数のクラスでコードを共有できる
  • 1つのクラスで複数のトレイトを同時に使える
  • メソッド名の衝突は insteadofas で解決する
  • 論理削除やタイムスタンプなど、横断的な機能に最適