Rešavanje konflikata metoda trejtova u OOP u PHP-u

Pošto jedna klasa može da koristi više trejtova, može da se pojavi problem kada dva trejta imaju metode sa istim imenom.

U tom slučaju PHP će prijaviti fatalnu grešku. Da bi se situacija ispravila, potrebno je eksplicitno razrešiti konflikt imena. Kako se to radi - pogledaćemo u praksi.

Neka imamo dva trejta sa istim metodom method:

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

Neka takođe imamo klasu Test, koja koristi oba naša trejta. Ako jednostavno povežemo oba trejta sa našom klasom, PHP će prijaviti grešku, jer trejtovi imaju podudarajuće metode:

php<?php
  // Ovaj kod će prijaviti grešku!
  class Test
  {
    use Trait1, Trait2; // povezujemo trejtove
  }
?>

Hajde da razrešimo konflikt imena naših trejtova. Za ovo postoji specijalni operator insteadof. Pomoću ovog operatora koristićemo metod method trejta Trait1 umesto istog metoda trejta Trait2:

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

Kao što vidite, sintaksa je sledeća: prvo ime trejta, onda dve tačke, onda ime metoda, onda naš operator insteadof i ime drugog trejta.

Hajde da proverimo:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // ispisaće 1, jer je to metod prvog trejta
    }
  }
  
  new Test;
?>

Dakle, u našoj klasi smo rekli da ako se koristi metod method, onda treba da se uzme iz prvog trejta. Može i obrnuto - uzeti metod drugog trejta:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait2::method insteadof Trait1;
    }
    
    public function __construct()
    {
      echo $this->method(); // ispisaće 2, jer je to metod drugog trejta
    }
  }
  
  new Test;
?>

U svakom slučaju, ako navedemo da se koristi metod jednog trejta, onda metod drugog trejta postaje nedostupan. Može se koristiti i metod drugog trejta, preimenujući ga preko ključne reči as, ovako:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method() + $this->method2(); // ispisaće 3
    }
  }
  
  new Test;
?>

Po želji se može preimenovati i metod prvog trejta:

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(); // ispisaće 3
    }
  }
  
  new Test;
?>

Korišćenje ključne reči as bez definisanja glavnog metoda preko insteadof je nemoguće, ovo će prijaviti grešku:

php<?php
  // Ova klasa će prijaviti grešku:
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method as method1;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method1() + $this->method2();
    }
  }
  
  new Test;
?>
Задание 1

Napravite 3 trejta sa nazivima Trait1, Trait2 i Trait3. Neka u prvom trejtu bude metod method, koji vraća 1, u drugom trejtu - metod sa istim imenom koji vraća 2, a u trećem trejtu - metod sa istim imenom koji vraća 3.

Задание 2

Napravite klasu Test, koja koristi sva tri napravljena trejta. Napravite u toj klasi metod getSum, koji vraća zbir rezultata metoda povezanih trejtova.