LoginSignup
9
8

More than 3 years have passed since last update.

【PHP】トレイトの基礎知識

Last updated at Posted at 2019-12-16

トレイトとは

トレイトとはなかなか聞き慣れない言葉ですが、いくつかの機能をまとめてコードを再利用するためのものです。
トレイトのメリットは、継承のようなis_a関係がなくとも機能を共有できるところにあります。
トレイとは以下のように宣言します。

トレイトの宣言

<?php
trait Hoge {
    public function sayHello() {
        echo 'Hello';
    }
}

クラスでトレイドのメソッドを使う

クラスでトレイとのメソッドを使用したいときは、useで宣言します。複数のトレイトを使用したいときは、カンマで区切ります。

public class foo {
    use Hoge;

    function sayHelloWorld() {
        echo $this->sayHello;
        echo 'World!';
    }
}

$foo = new Foo();
$foo->sayHelloWorld();
// HelloWorld!

また、トレイトはプロパティを定義したり、抽象メソッドを定義することもできます。

トレイド同士ののメソッドの競合

同じメソットを持つトレイトを複数インクルード使用しようとすると、fatal errorが発生します。

trait Hoge {
    public function sayHello() {
        echo 'Hello';
    }
}

trait Hogehoge {
    public function sayHello() {
        echo 'HELLO!!';
    }
}

class Foo {
    use Hoge, Hogehoge;

    public function sayHelloWorld() {
        echo $this->sayHello();
        echo 'World!';
    }
}

$foo = new Foo();
$foo->sayHelloWorld();

// Fatal error: Trait method sayHello has not been applied, because there are collisions with other trait methods on Foo

insteadofを使用し、どちらのメソッドを使用するか宣言することで、衝突を回避することができます。

trait Hoge {
    public function sayHello() {
        echo 'Hello';
    }
}

trait Hogehoge {
    public function sayHello() {
        echo 'HELLO!!';
    }
}

class Foo {
    use Hoge, Hogehoge {
        // 先頭は使用するトレイト 後ろは使わない方のトレイト
        Hogehoge::sayHello insteadof Hoge;
    }

    public function sayHelloWorld() {
        echo $this->sayHello();
        echo 'World!';
    }
}

$foo = new Foo();
$foo->sayHelloWorld();
// HELLO!!World!

使われないトレイトのメソッドは、asを使用してエイリアスを指定して使うことができます。

trait Hoge {
    public function sayHello() {
        echo 'Hello';
    }
}

trait Hogehoge {
    public function sayHello() {
        echo 'HELLO!!';
    }
}

class Foo {
    use Hoge, Hogehoge {
        Hogehoge::sayHello insteadof Hoge;
        Hoge::sayHello as hello;
    }

    public function sayHelloWorld() {
        echo $this->sayHello();
        echo 'World!';
        echo '<br>';
        echo $this->hello();
        echo 'World!';
    }
}

$foo = new Foo();
$foo->sayHelloWorld();

// HELLO!!World!
// HelloWorld!

また、asを用いることでメソッドの可視性も変更することが可能です。

trait Hoge {
    public function sayHello() {
        echo 'Hello';
    }
}

class Foo {
    use Hoge {
        sayHello as private;
    }
}

$foo = new Foo();
$foo->sayHelloWorld();
// Fatal error: Uncaught Error: Call to private method Foo::sayHello() from context

トレイトとクラスのメソッドの競合

こんどは、トレイトとクラス、さらにスーパクラスとの間でメソッドが競合しています。
どの結果が出力されるのでしょうか?

trait Hoge {
    public function sayHello() {
        echo 'Hello';
    }
}

class Par {
    public function sayHello() {
        echo 'HELLO';
    }
}

class Foo extends Par{
    use Hoge;

    public function sayHello() {
        echo 'Hello World!';
    }
}

$foo = new Foo();
$foo->sayHello();
// Hello World

これは、現在のクラスのメソッドのsayHello()の結果が出力されました。現在のクラスが優先度が最高です。
では、スーパークラスとトレイトの優先順位の関係はどうでしょうか?


trait Hoge {
    public function sayHello() {
        echo 'Hello';
    }
}

class Par {
    public function sayHello() {
        echo 'HELLO';
    }
}

class Foo extends Par{
    use Hoge;
}

$foo = new Foo();
$foo->sayHello();
// Hello

今度はトレイトのメソッドが勝ちました。
したがって優先順位は、現在のクラス > トレイト > スーパークラスとなります。

参考文献

公式
プログラミングPHP

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8