PHPにおけるOOPのトレイトメソッド競合の解決

1つのクラスが複数のトレイトを使用できるため、2つのトレイトが同じ名前のメソッドを持っている場合に問題が発生する可能性があります。

この場合、PHPは致命的なエラーを出力します。状況を修正するには、名前の競合を明示的に解決する必要があります。実際にどのように行うかを見ていきましょう。

同じメソッド method を持つ2つのトレイトがあるとします:

php<?php
  trait Trait1
  {
    private function method()
    {
      return 1;
    }
  }
  
  trait Trait2
  {
    private function method()
    {
      return 2;
    }
  }
?>

また、両方のトレイトを使用する Test クラスがあるとします。単に両方のトレイトをクラスに接続すると、トレイトに重複するメソッドがあるため、PHPはエラーを出力します:

php<?php
  // このコードはエラーを出力します!
  class Test
  {
    use Trait1, Trait2; // トレイトを接続
  }
?>

トレイトの名前の競合を解決しましょう。このためには特別な演算子 insteadof が存在します。この演算子を使用して、トレイト Trait2 の同じメソッドの代わりにトレイト Trait1 のメソッド method を使用します:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
  }
  
  new Test;
?>

ご覧の通り、構文は次のとおりです:最初にトレイト名、次に2つのコロン、メソッド名、それから演算子 insteadof、そして2番目のトレイト名です。

確認してみましょう:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // 1を出力します。これは最初のトレイトのメソッドだからです
    }
  }
  
  new Test;
?>

つまり、クラスで、メソッド method が使用される場合、最初のトレイトから取得するように指示しました。逆に、2番目のトレイトのメソッドを取得することもできます:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait2::method insteadof Trait1;
    }
    
    public function __construct()
    {
      echo $this->method(); // 2を出力します。これは2番目のトレイトのメソッドだからです
    }
  }
  
  new Test;
?>

いずれの場合も、1つのトレイトのメソッドを使用するように指定すると、2番目のトレイトのメソッドは使用できなくなります。キーワード as を使用して名前を変更することで、2番目のトレイトのメソッドも使用できます:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method() + $this->method2(); // 3を出力します
    }
  }
  
  new Test;
?>

必要に応じて、最初のトレイトのメソッドの名前も変更できます:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
      Trait1::method as method1;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method1() + $this->method2(); // 3を出力します
    }
  }
  
  new Test;
?>

insteadof を使用してメインメソッドを定義せずにキーワード as を使用することはできません。これはエラーを引き起こします:

php<?php
  // このクラスはエラーを出力します:
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method as method1;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method1() + $this->method2();
    }
  }
  
  new Test;
?>
Задание 1

Trait1、Trait2、Trait3 という名前のトレイトを 3 つ作成してください。最初のトレイトには 1 を返すメソッド method を、2番目のトレイトには 2 を返す同名のメソッドを、3番目のトレイトには 3 を返す同名のメソッドを含めてください。

Задание 2

作成した3つすべてのトレイトを使用する Test クラスを作成してください。このクラスに、接続されたトレイトのメソッドの結果の合計を返すメソッド getSum を作成してください。