Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override trait function and call it from the overridden function?

Tags:

php

traits

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 :)

like image 502
Shu Avatar asked Aug 13 '12 17:08

Shu


People also ask

Can we override trait method in PHP?

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!

Can a trait extend a class PHP?

Only classes can be extended. Traits are not classes.

Can trait implement interface?

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.


2 Answers

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...

like image 172
ircmaxell Avatar answered Oct 08 '22 17:10

ircmaxell


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

like image 40
Yehosef Avatar answered Oct 08 '22 17:10

Yehosef