Riešenie konfliktov metód traitov v OOP v PHP

Keďže jedna trieda môže použiť niekoľko traitov, môžeme naraziť na problém, ktorý nastáva v prípade, že dva traity majú metódy s rovnakým názvom.

V takom prípade PHP vyhodí fatálnu chybu. Aby sme situáciu napravili, budeme musieť konflikt mien vyriešiť explicitne. Ako sa to robí - uvidíme v praxi.

Predpokladajme, že máme dva traity s rovnakou metódou method:

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

Predpokladajme tiež, že máme triedu Test, ktorá používa oba naše traity. Ak jednoducho pripojíme oba traity k našej triede, PHP vyhodí chybu, pretože traity majú konfliktné metódy:

php<?php
  // Tento kód vyhodí chybu!
  class Test
  {
    use Trait1, Trait2; // pripájame traity
  }
?>

Poďme vyriešiť konflikt mien našich traitov. Na to existuje špeciálny operátor insteadof. Pomocou tohto operátora budeme používať metódu method trait-u Trait1 namiesto rovnakej metódy trait-u Trait2:

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

Ako vidíte, syntax je nasledovná: najprv názov trait-u, potom dve dvojbodky, potom názov metódy, potom náš operátor insteadof a názov druhého trait-u.

Poďme to vyskúšať:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // vypíše 1, pretože to je metóda prvého trait-u
    }
  }
  
  new Test;
?>

Takže, v našej triede sme povedali, že ak sa používa metóda method, malo by sa brať z prvého trait-u. Môžeme to urobiť aj naopak - vziať metódu druhého trait-u:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait2::method insteadof Trait1;
    }
    
    public function __construct()
    {
      echo $this->method(); // vypíše 2, pretože to je metóda druhého trait-u
    }
  }
  
  new Test;
?>

V každom prípade, ak určíme použiť metódu jedného trait-u, metóda druhého trait-u sa stáva nedostupnou. Môžeme však použiť aj metódu druhého trait-u, ak ju premenujeme pomocou kľúčového slova as, takto:

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

V prípade potreby môžeme premenovať aj metódu prvého trait-u:

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(); // vypíše 3
    }
  }
  
  new Test;
?>

Použitie kľúčového slova as bez určenia hlavnej metódy pomocou insteadof nie je možné, vyhodilo by to chybu:

php<?php
  // Táto trieda vyhodí chybu:
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method as method1;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method1() + $this->method2();
    }
  }
  
  new Test;
?>
Задание 1

Vytvorte 3 traity s názvami Trait1, Trait2 a Trait3. Nech v prvom traite bude metóda method, vracajúca 1, v druhom traite - metóda s rovnakým názvom, vracajúca 2, a v treťom traite - metóda s rovnakým názvom, vracajúca 3.

Задание 2

Vytvorte triedu Test, používajúcu všetky tri nami vytvorené traity. Vytvorte v tejto triede metódu getSum, vracajúcu súčet výsledkov metód pripojených traitov.