Rezolvarea conflictelor metodelor traitelor în POO în PHP

Deoarece o clasă poate utiliza mai multe traituri, putem întâmpina o problemă care apare atunci când două traituri au metode cu același nume.

În acest caz, PHP va afișa o eroare fatală. Pentru a remedia situația, va trebui să rezolvăm conflictul de nume în mod explicit. Cum se face acest lucru - vom vedea în practică.

Să presupunem că avem două traituri cu aceeași metodă method:

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

Să presupunem că avem și o clasă Test, care utilizează ambele traituri ale noastre. Dacă pur și simplu conectăm ambele traituri la clasa noastră, atunci PHP va afișa o eroare, deoarece traiturile au metode care coincid:

php<?php
  // Acest cod va afișa o eroare!
  class Test
  {
    use Trait1, Trait2; // conectăm traiturile
  }
?>

Să rezolvăm conflictul de nume al traiturilor noastre. Pentru aceasta există un operator special insteadof. Cu ajutorul acestui operator vom folosi metoda method a traitului Trait1 în locul aceleiași metode a traitului Trait2:

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

După cum vedeți, sintaxa este următoarea: mai întâi numele traitului, apoi două puncte, apoi numele metodei, apoi operatorul nostru insteadof și numele celui de-al doilea trait.

Să verificăm:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // va afișa 1, deoarece aceasta este metoda primului trait
    }
  }
  
  new Test;
?>

Deci, în clasa noastră am spus că dacă se folosește metoda method, atunci trebuie să o luăm din primul trait. Se poate și invers - să luăm metoda celui de-al doilea trait:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait2::method insteadof Trait1;
    }
    
    public function __construct()
    {
      echo $this->method(); // va afișa 2, deoarece aceasta este metoda celui de-al doilea trait
    }
  }
  
  new Test;
?>

În orice caz, dacă specificăm să folosim metoda unui trait, atunci metoda celui de-al doilea trait devine indisponibilă. Se poate folosi și metoda celui de-al doilea trait, redenumind-o prin cuvântul cheie as, astfel:

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

Dacă se dorește, se poate redenumi și metoda primului trait:

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(); // va afișa 3
    }
  }
  
  new Test;
?>

Utilizarea cuvântului cheie as fără definirea metodei principale prin insteadof nu este permisă, acest lucru va afișa o eroare:

php<?php
  // Această clasă va afișa o eroare:
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method as method1;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method1() + $this->method2();
    }
  }
  
  new Test;
?>
Задание 1

Creați 3 traituri cu numele Trait1, Trait2 și Trait3. Să existe în primul trait o metodă method care returnează 1, în al doilea trait - o metodă cu același nume care returnează 2, iar în al treilea trait - o metodă cu același nume, care returnează 3.

Задание 2

Creați o clasă Test care utilizează toate cele trei traituri create de noi. Creați în această clasă o metodă getSum care returnează suma rezultatelor metodelor traiturilor conectate.