466 Stimmen

Wie überschreibt man eine Trait-Funktion und ruft sie von der überschriebenen Funktion aus auf?

Szenario:

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

Dieser Code funktioniert nicht, und ich kann keine Möglichkeit finden, eine Trait-Funktion aufzurufen, wie sie vererbt wurde. Ich habe versucht, aufzurufen self::calc($v) , static::calc($v) , parent::calc($v) , A::calc($v) und die folgenden:

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

class MyClass {
    use A {
        calc as traitcalc;
    }

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

Nichts funktioniert.

Gibt es eine Möglichkeit, um es zu machen, oder muss ich vollständig überschreiben die Trait-Funktion, die viel komplexer als diese ist :)

815voto

ircmaxell Punkte 159431

Ihre letzte war fast fertig:

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

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

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

Der Trait ist keine Klasse. Sie können nicht direkt auf seine Mitglieder zugreifen. Es ist im Grunde nur ein automatisches Kopieren und Einfügen...

25voto

Yehosef Punkte 17023

Wenn die Klasse die Methode direkt implementiert, wird sie die Traits-Version nicht verwenden. Was Sie vielleicht meinen, ist:

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

Da die untergeordneten Klassen die Methode nicht direkt implementieren, verwenden sie zunächst die Methode des Traits, wenn sie sonst die Methode der übergeordneten Klasse verwenden.

Wenn Sie möchten, kann der Trait eine Methode in der übergeordneten Klasse verwenden (vorausgesetzt, Sie wissen, dass die Methode dort vorhanden ist), z. B.

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)

Sie können auch Möglichkeiten vorsehen, die Trait-Methode außer Kraft zu setzen, aber dennoch auf sie zuzugreifen, und zwar wie folgt:

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

Sie können sich die Arbeit ansehen unter http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5

13voto

Kartik V Punkte 467

Ein alternativer Ansatz bei Interesse - mit einer zusätzlichen Zwischenklasse, um den normalen OOO-Weg zu nutzen. Dies vereinfacht die Verwendung mit übergeordnet::Methodenname

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

5voto

tarkhov Punkte 324

Verwendung eines anderen Merkmals:

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

5voto

Gannet Punkte 1025

Eine andere Variante: Definieren Sie zwei Funktionen in der Eigenschaft, eine geschützte, die die eigentliche Aufgabe ausführt, und eine öffentliche, die wiederum die geschützte Funktion aufruft.

Dies erspart es den Klassen, sich mit der 'use'-Anweisung herumschlagen zu müssen, wenn sie die Funktion überschreiben wollen, da sie die geschützte Funktion immer noch intern aufrufen können.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X