PHPのトレイトについて簡単な内容のまとめ

PHPのトレイトについて簡単な内容のまとめ

122 回閲覧されました

みなさんこんにちは、jonioです。

トレイトを使わないといけなくなったので調べました。

簡単な内容をメモとしてまとめました。

トレイトとは

再利用したい機能をまとめたものです。

トレイトの宣言

下記の書き方をして宣言します。

<?php
  trait Hoge {
    //ここに再利用したい機能を書く
  }

この場合のトレイト名は「Hoge」でトレイトの中にクラスのプロパティやメソッドに当たる物を書きます。(物という表現をするのはトレイトはクラスではないからです)

下記みたいな感じです。

<?php
  trait Hoge {
    public $world;
    
    public function hello() {
      echo 'こんにちは';
    }
  }

トレイトの利用

クラスの中で使い下記の書き方をします。

<?php
  trait Hoge {
    public $world;
    
    public function hello() {
      echo 'こんにちは';
    }
  }

  class Huga {
    use Hoge;
  
    public function useTrait() {
      echo $this->hello();
    }
  }
  
  $instance = new Huga();
  $instance->useTrait();
  
  //出力結果は「こんにちは」

11行目でトレイトを使う宣言をします。

「Hoge」はトレイト名です。

14行目でトレイトの中のhelloメソッドを使っています、「$this->トレイト名」で使えます。

トレイトの競合

トレイトを使う時に下記の書き方をすれば複数使うことができます。

<?php
  trait Hoge {
    public function hello() {
      echo 'こんにちは';
    }
  }
  
  trait HogeHoge {
    public function hello() {
      echo 'こんばんは';
    }
  }

  class Huga {
    use Hoge, HogeHoge;
    
    public function useTrait() {
      echo $this->hello();
    }
  }
  
  $instance = new Huga();
  $instance->useTrait();
  
  //出力結果はエラー

15行目です、セミコロン(,)で区切って使うことができますが注意点があります。

HogeトレイトとHogeHogeトレイトに共通のメソッド(hello)があります。

共通のメソッドがあるトレイトを使うとエラーになります。

使うトレイトを指定

下記の書き方をすればいいです。

<?php
  trait Hoge {
    public function hello() {
      echo 'こんにちは';
    }
  }
  
  trait HogeHoge {
    public function hello() {
      echo 'こんばんは';
    }
  }

  class Huga {
    use Hoge, HogeHoge {
      Hogehoge::hello insteadof Hoge;     //この行を追加
    }
    
    public function useTrait() {
      echo $this->hello;
    }
  }
  
  $instance = new Huga();
  $instance->useTrait();
  
  //出力結果はこんばんは

16行目を追加します。

「::hello」の前に書くのが使うトレイトで「insteadof」の後ろに書くのが使わないトレイトです。

トレイトを共存

確かにこのやり方をすればトレイトを使えますが片方のトレイトを使わないなら最初から1つだけしかトレイトを使わなければ問題ありません。

下記の追記をすれば使わないトレイトも使うことができます。

<?php
  trait Hoge {
    public function hello() {
      echo 'こんにちは';
    }
  }
  
  trait HogeHoge {
    public function hello() {
      echo 'こんばんは';
    }
  }

  class Huga {
    use Hoge, HogeHoge {
      Hogehoge::hello insteadof Hoge;
      Hoge::hello as notUse;       //この行を追加
    }
    
    public function useTrait() {
      echo $this->hello;
      
      echo $this->notUse;     //この行を追加
    }
  }
  
  $instance = new Huga();
  $instance->useTrait();
  
  //出力結果はこんばんは、こんにちは

17行目、23行目を追記します。

17行目で使わないトレイト(Hoge)を「as」を使ってnotUseに名前を変更しましたがこれをすれば使わないトレイトを使うことができます。

トレイトとクラスの競合

トレイトとクラスのメソッドが競合した場合を考えます。

この場合はエラーになりません。

下記の記述をしたとします。

<?php
  trait Hoge {
    public function hello() {
      echo 'こんにちは';
    }
  }

  class Huga {
    use Hoge;
  
    public function hello() {
      echo 'こんばんは';
    }
  }
  
  $instance = new Huga();
  $instance->hello();
  
  //出力結果は「こんばんは」

トレイトとクラスのメソッドが競合した場合はクラスのメソッドが呼び出されます。

トレイトと親クラスの競合

トレイトと親クラスのメソッドが競合した場合を考えます。

この場合もエラーになりません。

下記の記述をしたとします。

<?php
  trait Hoge {
    public function hello() {
      echo 'こんにちは';
    }
  }

  class Parent {
    use Hoge;
  
    public function hello() {
      echo 'こんばんは';
    }
  }
  
  class Child extends Parent {
  }
  
  $instance = new Parent();
  $instance->hello();
  
  //出力結果は「こんにちは」

トレイトと親クラスのメソッドが競合した場合はトレイトのメソッドが呼び出されます。