Вырашэнне канфліктаў метадаў трэйтаў у ААП у PHP

Так як адзін клас можа выкарыстоўваць некалькі трэйтаў, то нас можа падпікаваць праблема, якая ўзнікае тады, калі два трэйты маюць аднайменныя метады.

У гэтым выпадку PHP выдасць фатальную памылку. Каб паправіць сітуацыю, трэба будзе вырашыць канфлікт імяў явным чынам. Як гэта робіцца - паглядзім на практыцы.

Хай у нас ёсць два трэйты з аднолькавым метадам method:

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. З дапамогай гэтага аператара будзем выкарыстоўваць метад method трэйта Trait1 замест такога ж метаду трэйта Trait2:

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

Як вы бачыце, сінтаксіс тут наступны: спачатку імя трэйта, потым два двукроп'і, потым імя метаду, потым наш аператар insteadof і імя другога трэйта.

Давайце праверым:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // вывядзе 1, бо гэта метад першага трэйта
    }
  }
  
  new Test;
?>

Такім чынам, у нашым класе мы сказалі, што калі выкарыстоўваецца метад method, то варта браць яго з першага трэйта. Можна і наадварот - узяць метад другога трэйта:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait2::method insteadof Trait1;
    }
    
    public function __construct()
    {
      echo $this->method(); // вывядзе 2, бо гэта метад другога трэйта
    }
  }
  
  new Test;
?>

У любым выпадку, калі мы паказваем выкарыстоўваць метад аднаго трэйта, то метад другога трэйта аказваецца недаступным. Можна выкарыстоўваць і метад другога трэйта, перайменаваўшы яго праз ключавое слова as, вось так:

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;
?>

Выкарыстоўваць ключавое слова as без вызначэння галоўнага метаду праз insteadof нельга, гэта выдасць памылку:

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

Зрабіце 3 трэйты з назвамі Trait1, Trait2 і Trait3. Хай у першым трэйце будзе метад method, які вяртае 1, у другім трэйце - аднайменны метад, які вяртае 2, а ў трэцім трэйце - аднайменны метад, які вяртае 3.

Задание 2

Зрабіце клас Test, які выкарыстоўвае ўсе тры створаныя намі трэйты. Зрабіце ў гэтым класе метад getSum, які вяртае суму вынікаў метадаў падключаных трэйтаў.