PHP - trait

公開日:2020-12-22 更新日:2020-12-22
[PHP]

1. 概要

trait を使うと、クラスを継承せずに、他のクラスとメソッドを共有できます。
メソッドをクラス外のトレイトで定義して、それをクラスに取り込むイメージです。
トレイトは、クラスのようにメソッドを定義して、使う時は、クラス内で use で指定します。
トレイトでは、クラスを static、インスタンスを $this で参照できます。
トレイトの時点では存在しないクラスのメソッドやプロパティを使用することもできます。
trait トレイト名 {
    function メソッド名1() { }
    function メソッド名2() { }
}
class クラス名1 {
    use トレイト名;
}
class クラス名2 {
    use トレイト名;
}

2. 使用例

Test1クラスとTest2クラスで、Utilsトレイトのメソッドを呼び出しています。
trait Utils {
    public function getClassName() {
        return get_class($this); // $this でクラスのインスタンスを参照可能
    }
    public function getMsg() {
        return $this->msg; // trait にないプロパティやメソッドも参照可能
                           // 実行時にプロパティがない場合はエラー
    }
    public static function getInstance() {
        return new static(); // インスタンスの生成
                             // trait 内ではクラス名が特定できないため、static を使用する
    }
}
class Test1 {
    use Utils;
    private $msg = 'おはよう';
}
class Test2 {
    use Utils;
    private $msg = 'こんにちは';
}

$obj1 = new Test1();
var_dump($obj1->getClassName());
var_dump($obj1->getMsg());

$obj2 = Test2::getInstance(); // new Test2();
var_dump($obj2->getClassName());
var_dump($obj2->getMsg());
実行結果
string(5) "Test1"
string(12) "おはよう"
string(5) "Test2"
string(15) "こんにちは"

3. 使用例

トレイトは、複数使用することができます。
トレイトのメソッドが重複した場合は、insteadof を使って、どちらか片方のメソッドを有効にします。
trait Trait1 {
    public function getMsg() {
        return 'Trait1';
    }
}
trait Trait2 {
    public function getMsg() {
        return 'Trait2';
    }
    public function hello() {
        return 'hello';
    }
}

class Test1 {
    use Trait1, Trait2 {
        Trait1::getMsg insteadof Trait2; // Trait1::getMsg を有効にする
    }
}

$obj1 = new Test1();
var_dump($obj1->getMsg());
var_dump($obj1->hello());
実行結果
string(6) "Trait1"
string(5) "hello"