Scenario:
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
This code doesn't work, and I cannot find a way to call a trait function like it was inherited. I tried calling self::calc($v)
, static::calc($v)
, parent::calc($v)
, A::calc($v)
and the following:
trait A { function calc($v) { return $v+1; } } class MyClass { use A { calc as traitcalc; } function calc($v) { $v++; return traitcalc($v); } }
Nothing works.
Is there a way to make it work or must I override completely the trait function which is much more complex than this :)
Traits are a useful way of keeping our code DRY (i.e. not repeating ourselves) and sharing methods amongst classes. The fact that we can override and extend the methods from a trait makes them extremely useful!
Only classes can be extended. Traits are not classes.
Traits reduces the complexity, and avoids problems associated with multiple inheritance and Mixins. Note that PHP does not allow multiple inheritance. So Traits is used to fulfill this gap by allowing us to reuse same functionality in multiple classes. Traits can not implement interfaces.
Your last one was almost there:
trait A { function calc($v) { return $v+1; } } class MyClass { use A { calc as protected traitcalc; } function calc($v) { $v++; return $this->traitcalc($v); } }
The trait is not a class. You can't access its members directly. It's basically just automated copy and paste...
If the class implements the method directly, it will not use the traits version. Perhaps what you are thinking of is:
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
Because the child classes do not implement the method directly, they will first use that of the trait if there otherwise use that of the parent class.
If you want, the trait can use method in the parent class (assuming you know the method would be there) e.g.
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)
You can also provide for ways to override, but still access the trait method as follows:
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
You can see it work at http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With