web-dev-qa-db-ja.com

トレイト関数をオーバーライドして、オーバーライドされた関数から呼び出す方法

シナリオ:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A;

    function calc($v) {
        $v++;
        return A::calc($v);
    }
}

print (new MyClass())->calc(2); // should print 4

このコードは動作しません、そして私はそれが継承されたようにトレイト関数を呼び出す方法を見つけることができません。私はself::calc($v)static::calc($v)parent::calc($v)A::calc($v)、そして以下を呼び出してみました。

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as traitcalc;
    }

    function calc($v) {
        $v++;
        return traitcalc($v);
    }
}

何も動作しません。

それを機能させる方法はありますか、それともはるかに複雑なトレイト関数を完全にオーバーライドする必要がありますか:)

327
Shu

あなたの最後のものはほとんどそこにありました:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as protected traitcalc;
    }

    function calc($v) {
        $v++;
        return $this->traitcalc($v);
    }
}

特性はクラスではありません。あなたはそのメンバーに直接アクセスすることはできません。基本的には自動コピー&ペーストだけです。

563
ircmaxell

クラスがメソッドを直接実装する場合は、特性バージョンを使用しません。おそらくあなたが考えているのは:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}

class MyChildClass extends MyClass{
}

class MyTraitChildClass extends MyClass{
    use A;
}

print (new MyChildClass())->calc(2); // will print 4

print (new MyTraitChildClass())->calc(2); // will print 3

子クラスはメソッドを直接実装していないため、他の方法で親クラスのメソッドを使用する場合は、最初にトレイトの特性を使用します。

必要に応じて、トレイトは親クラスのメソッドを使うことができます(メソッドがそこにあることを知っていると仮定して)。

trait A {
    function calc($v) {
        return parent::calc($v*3);
    }
}
// .... other code from above
print (new MyTraitChildClass())->calc(2); // will print 8 (2*3 + 2)

オーバーライドする方法を提供することもできますが、それでも次のようにtraitメソッドにアクセスします。

trait A {
    function trait_calc($v) {
        return $v*3;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}


class MyTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }
}


class MySecondTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }

    public function calc($v) {
      return $this->trait_calc($v)+.5;
    }
}


print (new MyTraitChildClass())->calc(2); // will print 6
echo "\n";
print (new MySecondTraitChildClass())->calc(2); // will print 6.5

あなたはそれがで動作するのを見ることができます http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5

10
Yehosef

興味があるなら代替のアプローチ - 通常のOOOの方法を使うための追加の中間クラスを使う。これはparent :: methodnameを使った使い方を単純化します

trait A {
    function calc($v) {
        return $v+1;
    }
}

// an intermediate class that just uses the trait
class IntClass {
    use A;
}

// an extended class from IntClass
class MyClass extends IntClass {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}
7
Kartik V

他の特性を使う:

trait ATrait {
    function calc($v) {
        return $v+1;
    }
}

class A {
    use ATrait;
}

trait BTrait {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}

class B extends A {
    use BTrait;
}

print (new B())->calc(2); // should print 4
0
tarkhov