web-dev-qa-db-fra.com

Comment remplacer la fonction de trait et l'appeler depuis la fonction remplacée?

Scénario:

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

Ce code ne fonctionne pas et je ne trouve pas le moyen d'appeler une fonction de trait comme si elle avait été héritée. J'ai essayé d'appeler self::calc($v), static::calc($v), parent::calc($v), A::calc($v) et les suivantes:

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

class MyClass {
    use A {
        calc as traitcalc;
    }

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

Rien ne fonctionne.

Y at-il un moyen de le faire fonctionner ou dois-je remplacer complètement la fonction trait qui est beaucoup plus complexe que cela :)

335
Shu

Votre dernier était presque là:

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

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

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

Le trait n'est pas une classe. Vous ne pouvez pas accéder directement à ses membres. C'est fondamentalement juste un copier-coller automatisé ...

584
ircmaxell

Si la classe implémente directement la méthode, elle n'utilisera pas la version de traits. Peut-être ce que vous pensez est:

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

Comme les classes enfants n'implémentent pas directement la méthode, elles utiliseront d'abord celle de la caractéristique si elles utilisent autrement celle de la classe parente.

Si vous le souhaitez, le trait peut utiliser la méthode de la classe parente (en supposant que vous savez que la méthode serait présente), par exemple.

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)

Vous pouvez également fournir des moyens de remplacer, mais toujours accéder à la méthode trait de la manière suivante:

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

Vous pouvez le voir fonctionner à l'adresse http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5

10
Yehosef

Une approche alternative si vous êtes intéressé - avec une classe intermédiaire supplémentaire pour utiliser la méthode OOO normale. Cela simplifie l'utilisation avec 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

Utiliser un autre trait:

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