Rozwiązywanie konfliktów metod traitów w OOP w PHP

Ponieważ jedna klasa może używać kilku traitów, może nas spotkać problem, który powstaje, gdy dwa traity mają metody o tej samej nazwie.

W tym przypadku PHP zwróci błąd fatalny. Aby naprawić sytuację, konieczne będzie jawne rozwiązanie konfliktu nazw. Jak to się robi - zobaczymy w praktyce.

Załóżmy, że mamy dwa traity z identyczną metodą method:

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

Załóżmy również, że mamy klasę Test, używającą obu naszych traitów. Jeśli po prostu podłączymy oba traity do naszej klasy, PHP zwróci błąd, ponieważ traity mają zbieżne metody:

php<?php
  // Ten kod zwróci błąd!
  class Test
  {
    use Trait1, Trait2; // podłączamy traity
  }
?>

Rozwiążmy konflikt nazw naszych traitów. Służy do tego specjalny operator insteadof. Za pomocą tego operatora będziemy używać metody method traita Trait1 zamiast takiej samej metody traita Trait2:

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

Jak widzicie, składnia jest następująca: najpierw nazwa traita, potem dwa dwukropki, potem nazwa metody, potem nasz operator insteadof i nazwa drugiego traita.

Sprawdźmy:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // wyświetli 1, bo to metoda pierwszego traita
    }
  }
  
  new Test;
?>

A więc, w naszej klasie powiedzieliśmy, że jeśli używana jest metoda method, to należy brać ją z pierwszego traita. Można i odwrotnie - wziąć metodę drugiego traita:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait2::method insteadof Trait1;
    }
    
    public function __construct()
    {
      echo $this->method(); // wyświetli 2, bo to metoda drugiego traita
    }
  }
  
  new Test;
?>

W każdym przypadku, jeśli wskażemy użycie metody jednego traita, to metoda drugiego traita staje się niedostępna. Można użyć i metody drugiego traita, zmieniając jej nazwę poprzez słowo kluczowe as, w ten sposób:

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

W razie potrzeby można zmienić nazwę i metody pierwszego traita:

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(); // wyświetli 3
    }
  }
  
  new Test;
?>

Użycie słowa kluczowego as bez zdefiniowania metody głównej poprzez insteadof jest niemożliwe, spowoduje to błąd:

php<?php
  // Ta klasa zwróci błąd:
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method as method1;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method1() + $this->method2();
    }
  }
  
  new Test;
?>
Задание 1

Stwórz 3 traity o nazwach Trait1, Trait2 i Trait3. Niech w pierwszym traicie będzie metoda method, zwracająca 1, w drugim traicie - jednomonimiczna metoda, zwracająca 2, a w trzecim traicie - jednomonimiczna metoda, zwracająca 3.

Задание 2

Stwórz klasę Test, używającą wszystkich trzech stworzonych przez nas traitów. Stwórz w tej klasie metodę getSum, zwracającą sumę wyników metod podłączonych traitów.