Решавање конфликта метода трејтова у ООП у 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 који враћа збир резултата метода повезаних трејтова.