Traittien menetelmäristiriitojen ratkaiseminen OOP:ssa PHP:ssä

Koska yksi luokka voi käyttää useita traitteja, voi meitä odottaa ongelma, joka syntyy, kun kahdella traitilla on samanimiset menetelmät.

Tässä tapauksessa PHP antaa vakavan virheen. Korjataksemme tilanteen, meidän on ratkaistava nimiristiriita eksplisiittisesti. Miten tämä tehdään - katsotaan käytännössä.

Oletetaan, että meillä on kaksi traitia, joilla on sama menetelmä method:

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

Oletetaan myös, että meillä on luokka Test, joka käyttää molempia traittejamme. Jos yksinkertaisesti liitämme molemmat traitit luokkaamme, niin PHP antaa virheen, koska traiteilla on päällekkäisiä menetelmiä:

php<?php
  // Tämä koodi antaa virheen!
  class Test
  {
    use Trait1, Trait2; // liitetään traitit
  }
?>

Ratkaistaan traittiemme nimiristiriita. Tätä varten on olemassa erityinen operaattori insteadof. Tämän operaattorin avulla käytämme traitin Trait1 menetelmää method saman menetelmän sijasta traitissa Trait2:

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

Kuten näette, syntaksi on seuraava: aluksi traitin nimi, sitten kaksi kaksoispistettä, sitten menetelmän nimi, sitten operaattorimme insteadof ja toisen traitin nimi.

Testataan:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method insteadof Trait2;
    }
    
    public function __construct()
    {
      echo $this->method(); // tulostaa 1, koska tämä on ensimmäisen traitin menetelmä
    }
  }
  
  new Test;
?>

Joten, luokassamme sanoimme, että jos käytetään menetelmää method, tulee ottaa se ensimmäisestä traitista. Voimme tehdä myös päinvastoin - ottaa toisen traitin menetelmän:

php<?php
  class Test
  {
    use Trait1, Trait2 {
      Trait2::method insteadof Trait1;
    }
    
    public function __construct()
    {
      echo $this->method(); // tulostaa 2, koska tämä on toisen traitin menetelmä
    }
  }
  
  new Test;
?>

Joka tapauksessa, jos määritämme käytettäväksi yhden traitin menetelmän, niin toisen traitin menetelmä ei ole käytettävissä. Voimme kuitenkin käyttää myös toisen traitin menetelmää, nimeämällä sen uudelleen avainsanalla as, näin:

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

Halutessamme voimme nimetä uudelleen myös ensimmäisen traitin menetelmän:

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

Avainsanan as käyttäminen ilman päämenetelmän määrittelyä insteadof:lla ei ole sallittua, se aiheuttaa virheen:

php<?php
  // Tämä luokka antaa virheen:
  class Test
  {
    use Trait1, Trait2 {
      Trait1::method as method1;
      Trait2::method as method2;
    }
    
    public function __construct()
    {
      echo $this->method1() + $this->method2();
    }
  }
  
  new Test;
?>
Задание 1

Tee 3 traitia nimillä Trait1, Trait2 ja Trait3. Olkoon ensimmäisessä traitissa menetelmä method, joka palauttaa 1, toisessa traitissa - samaniminen menetelmä, joka palauttaa 2, ja kolmannessa traitissa - samaniminen menetelmä, joka palauttaa 3.

Задание 2

Tee luokka Test, joka käyttää kaikkia kolmea tekemäämme traitia. Tee tähän luokkaan menetelmä getSum, joka palauttaa liitettyjen traittien menetelmien tulosten summan.