web-dev-qa-db-ja.com

PHPトレイトメソッドの競合:トレイト「継承」とトレイト階層

UPDATE:この問題について熟考しているのは私だけではなく、確かにバグのようです。 ここ を参照してください。修正された日は素晴らしい日になるでしょう! :)


これはI love PHP traits! I'm going to use them everywhere! ^_^として始まり、現在はThought Exercise / Learning Experience >_<になっています。

次の例を考えてみましょう。

trait TheErrorOfYourWays{

   public function booboo(){
       echo 'You had a booboo :(';
   }
}

trait SpectacularStuff1 {
    use TheErrorOfYourWays; 
}

trait SpectacularStuff2 {
    use TheErrorOfYourWays;
}

class DoSomethingSpectacular {
    use SpectacularStuff1, SpectacularStuff2;
}

これにより、(明らかに それほど明白ではありません):

致命的なエラー:DoSomethingSpectacularで他のトレイトメソッドとの衝突があるため、トレイトメソッドboobooは適用されていません。

それで私の質問:特性のメソッドの競合を解決するにはどうすればよいですか?重複する特性「継承」を実現することは可能ですか?もしそうなら、これを行うための「正しい」方法は何ですか?

なぜこれをしたいのか:

  1. 自己完結型の特性とクラス(ミックスアンドマッチスタイル)を作成したい。 可能であれば「使う」と言いたいので、魔法のようなことが起こらなければなりません。頭をかいて、「その特性はどの名前空間に戻ったのか」などと考える必要はありません。
  2. 「冒険的」なことをして、うっかりして競合が発生したことに気付いたときに、クラスや特性をその場で編集する必要はありません。
  3. 当時は良い考えのようでした。

私が試したこと:

  1. PHPマニュアル。
  2. グーグル。
  3. SOを含む この質問 ->このシナリオの正解ではありません。
  4. これが見つかりました しかし私はPHPバージョン5.5.1を使用しています。修正されましたよね?そうですか?
  5. さまざまな場所、時間、宇宙などでの「as」、エイリアスの素晴らしい配列。以下を含みますが、これらに限定されません。

    trait SpectacularStuff1 {
       use TheErrorOfYourWays{
          TheErrorOfYourWays::booboo as booboo1;
       }
    }
    trait SpectacularStuff2 {
       use TheErrorOfYourWays{
          TheErrorOfYourWays::booboo as booboo2;
       }
    }
    class DoSomethingSpectacular {
       use SpectacularStuff1, SpectacularStuff2 {
          /* Tried separately, but included here for brevity's sake */
          SpectacularStuff1::booboo as booboo3;
          SpectacularStuff2::booboo as booboo4;
       }
    }
    

    そして

    use TheErrorOfYourWays as Erroneous1;
    trait SpectacularStuff1 {
        use Erroneous1{
            Erroneous1::booboo as booboo1;
        }
    }
    
    use TheErrorOfYourWays as Erroneous2;
    trait SpectacularStuff2 {
        use Erroneous2{
            Erroneous2::booboo as booboo2;
        }
    }
    

私はそれを理解しています:

  1. TheErrorOfYourWaysをクラスに変更して、booboo()を静的にすることはできますが、この特定の特性の動作について学びたいと思います。
  2. トレイトからTheErrorOfYourWaysを削除してクラスで使用することはできますが、それは「自己完結型」ではありません。クラスから直接booboo()を呼び出さなくても、トレイトを使用するたびに、クラスでTheErrorOfYourWaysを使用することを忘れないでください。危険そうですね。
  3. 私はおそらく、ルーキー構文エラーを犯したか、深刻なレベルでエイリアシングを理解できませんでした。もしそうなら、お願いします...説明...ゆっくり...
  4. これを行うにはおそらくもっと良い方法があります。もしそうなら、お願いします...説明...ゆっくり...
  5. 私は時期尚早に熱狂しているかもしれません、そしてPHPはまだこれをしていません。私をそっと失望させてください。

ありがとう!

24
Just Plain High

したがって、 非公式の「公式」回答 は次のとおりです。

エイリアシングなしで、または何もせずにそれを行うことができます!しかし、まだ...

5.5.1から5.5.6にアップグレードしましたが、すべて無駄でした。修正が利用可能になったら、この回答を更新します。興味深いことに、trait静的関数を直接呼び出すことができます。次の例が機能します。

trait TheErrorOfYourWays{
    public static function booboo($thisTrait){
        echo 'You had a booboo :( in '.$thisTrait.'<br>';
    }
}

trait SpectacularStuff1 {
    public function boobooTest1(){
        TheErrorOfYourWays::booboo(__TRAIT__);
    }
}

trait SpectacularStuff2 {
    public function boobooTest2(){
        TheErrorOfYourWays::booboo(__TRAIT__);
    }
}

class DoSomethingSpectacular {
    use SpectacularStuff1, SpectacularStuff2;
}

$boobooAChoo = new DoSomethingSpectacular();
$boobooAChoo->boobooTest1(); // You had a booboo :( in SpectacularStuff1
$boobooAChoo->boobooTest2(); // You had a booboo :( in SpectacularStuff2

はい、はい、クラスでもそれを行うことができますが、クラスは昨シーズンsooooです。

4
Just Plain High

トレイトの競合を解決するには、キーワードinsteadofを使用する必要があります。

Source

あなたの書き直し

class DoSomethingSpectacular {
   use SpectacularStuff1, SpectacularStuff2 {
      /* Tried separately, but included here for brevity's sake */
      SpectacularStuff1::booboo as booboo3;
      SpectacularStuff2::booboo as booboo4;
   }
}

to

class DoSomethingSpectacular {
    use SpectacularStuff1, SpectacularStuff2 
    {
     SpectacularStuff1::booboo insteadof SpectacularStuff2;
     SpectacularStuff2::booboo insteadof SpectacularStuff1;
    }
}

競合を解決します。

21

私はこれを一時的に修正する別の方法を見つけました:

trait A {
   public function foo(){
       echo 'foo';
   }
}

trait B {
   public function foofoo(){
       return $this->foo () . 'foo';
   }
}

trait C {
   public function foobar(){
       return $this->foo () . 'bar';
   }
}

class DoSomethingSpectacular {
    use A, B, C;

    public function foobarfoofoo () {
        echo $this->foobar () . $this->foofoo ();
    }
}

そしてそれは動作します:)

1
IAmJulianAcosta

ちょっとしたハック、関数boobooをクラスDoSomethingSpectacularに追加するだけです

<?php
trait TheErrorOfYourWays{

   public function booboo(){
       echo 'You had a booboo :(';
   }
}

trait SpectacularStuff1 {
   use TheErrorOfYourWays{
      TheErrorOfYourWays::booboo as booboo1;
   }
}

trait SpectacularStuff2 {
   use TheErrorOfYourWays{
      TheErrorOfYourWays::booboo as booboo2;
   }
}
class DoSomethingSpectacular {
   use SpectacularStuff1, SpectacularStuff2 {
      /* Tried separately, but included here for brevity's sake */
      SpectacularStuff1::booboo as booboo3;
      SpectacularStuff2::booboo as booboo4;
   }

  //very ugly hack
  public function booboo() {}
}
0
Hałas piotr