Řešení konfliktů metod traitů v OOP v PHP

Protože jedna třída může používat několik traitů, může nás potkat problém, který nastane, když dva traity mají metody se stejným názvem.

V tomto případě PHP vypíše fatální chybu. Abychom situaci napravili, bude nutné konflikt jmen explicitně vyřešit. Jak se to dělá - podíváme se v praxi.

Předpokládejme, že máme dva traity se stejnou metodou method:

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

Předpokládejme také, že máme třídu Test, používající oba naše traity. Pokud jednoduše připojíme oba traity k naší třídě, PHP vypíše chybu, protože traity mají shodné metody:

php<?php
  // Tento kód vypíše chybu!
  class Test
  {
    use Trait1, Trait2; // připojujeme traity
  }
?>

Pojďme vyřešit konflikt jmen našich traitů. K tomu existuje speciální operátor insteadof. Pomocí tohoto operátoru budeme používat metodu method traitu Trait1 namísto stejné metody traitu Trait2:

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

Jak vidíte, syntaxe je následující: nejprve název traitu, pak dvě dvojtečky, pak název metody, pak náš operátor insteadof a název druhého traitu.

Pojďme to ověřit:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // vypíše 1, protože to je metoda prvního traitu
    }
  }
  
  new Test;
?>

Takže v naší třídě jsme řekli, že pokud se použije metoda method, měla by se brát z prvního traitu. Lze to i naopak - vzít metodu druhého traitu:

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

V každém případě, pokud určíme používat metodu jednoho traitu, pak metoda druhého traitu je nedostupná. Lze použít i metodu druhého traitu, přejmenovat ji pomocí klíč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 případě potřeby lze přejmenovat i metodu prvního traitu:

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žití klíčového slova as bez určení hlavní metody pomocí insteadof není možné, vypíše to chybu:

php<?php
  // Tato třída vypíše 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

Vytvořte 3 traity s názvy Trait1, Trait2 a Trait3. Nechť v prvním traitu bude metoda method, vracející 1, v druhém traitu - stejnojmenná metoda, vracející 2, a ve třetím traitu - stejnojmenná metoda, vracející 3.

Задание 2

Vytvořte třídu Test, používající všechny tři vytvořené traity. Vytvořte v této třídě metodu getSum, vracející součet výsledků metod připojených traitů.