428

シナリオ:

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);
    }
}

何も機能しません。

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

4

5 に答える 5

745

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

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

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

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

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

于 2012-08-13T17:30:31.810 に答える
17

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

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 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で動作するのを見ることができます

于 2014-06-08T13:00:32.423 に答える
13

興味がある場合の代替アプローチ-通常の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);
    }
}
于 2015-06-08T05:04:18.393 に答える
4

別の特性を使用する:

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
于 2017-08-20T22:27:04.923 に答える
4

別のバリエーション:トレイトに2つの関数を定義します。実際のタスクを実行する保護された関数と、保護された関数を呼び出すパブリック関数です。

これにより、保護された関数を内部で呼び出すことができるため、クラスが関数をオーバーライドする場合に「use」ステートメントをいじる必要がなくなります。

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

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

class MyClass {
    use A;

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

class MyOtherClass {
    use A;
}


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

print (new MyOtherClass())->calc(2); // will print 3
于 2020-08-09T23:52:44.620 に答える