PHP trait method conflicts: trait "inheritance" and trait hierarchies
Solution 1
So the unofficial "official" answer is:
You can do it without aliasing, insteadof or anything! But not yet...
I upgraded from 5.5.1 to 5.5.6 but it was all in vain. I will update this answer when the fix becomes available. Interesting to note is that you can call trait static functions directly. The following example works:
trait TheErrorOfYourWays{
public static function booboo($thisTrait){
echo 'You had a booboo :( in '.$thisTrait.'<br>';
}
}
trait SpectacularStuff1 {
public function boobooTest1(){
TheErrorOfYourWays::booboo(__TRAIT__);
}
}
trait SpectacularStuff2 {
public function boobooTest2(){
TheErrorOfYourWays::booboo(__TRAIT__);
}
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2;
}
$boobooAChoo = new DoSomethingSpectacular();
$boobooAChoo->boobooTest1(); // You had a booboo :( in SpectacularStuff1
$boobooAChoo->boobooTest2(); // You had a booboo :( in SpectacularStuff2
Yes, yes, you can also do that with a class but classes are soooo last season.
Solution 2
You need to make use of the keyword insteadof
to resolve the conflicts in Traits.
Rewriting your
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2 {
/* Tried separately, but included here for brevity's sake */
SpectacularStuff1::booboo as booboo3;
SpectacularStuff2::booboo as booboo4;
}
}
to
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2
{
SpectacularStuff1::booboo insteadof SpectacularStuff2;
SpectacularStuff2::booboo insteadof SpectacularStuff1;
}
}
will resolve the conflicts.
Solution 3
I found another way to fix temporary this:
trait A {
public function foo(){
echo 'foo';
}
}
trait B {
public function foofoo(){
return $this->foo () . 'foo';
}
}
trait C {
public function foobar(){
return $this->foo () . 'bar';
}
}
class DoSomethingSpectacular {
use A, B, C;
public function foobarfoofoo () {
echo $this->foobar () . $this->foofoo ();
}
}
And it works :)
Related videos on Youtube
Just Plain High
Updated on June 14, 2022Comments
-
Just Plain High almost 2 years
UPDATE: I am not alone in my pondering on this issue and it seems it is indeed a bug. See here. The day it is fixed is going to be a fantastic day! :)
This started out as
I love PHP traits! I'm going to use them everywhere! ^_^
and now it has turned into aThought Exercise / Learning Experience >_<
.Consider the following example:
trait TheErrorOfYourWays{ public function booboo(){ echo 'You had a booboo :('; } } trait SpectacularStuff1 { use TheErrorOfYourWays; } trait SpectacularStuff2 { use TheErrorOfYourWays; } class DoSomethingSpectacular { use SpectacularStuff1, SpectacularStuff2; }
This results in (
obviouslynot so obviously):Fatal error: Trait method booboo has not been applied, because there are collisions with other trait methods on DoSomethingSpectacular.
So my question: How do I resolve method conflicts in traits? Is it possible to achieve overlapping trait "inheritance"? If so, what is the "right" way to do this?
Why I want to do this:
- I want to create self contained traits and classes (mix and match style). If it is at all possible, I want to say "use" and then magic stuff must happen. No having to scratch my head and think, "Now what namespace was that trait in again?", etc, etc.
- No having to edit classes and traits on the fly when I do something "adventurous" and discover I have inadvertently created a conflict.
- Seemed like a good idea at the time.
What I have tried:
- The PHP Manual.
- The Google.
- SO including this question -> Not the correct answer for this scenario.
- Found this but I am using PHP version 5.5.1. It's fixed, right? Right?
-
A fantastic array of "as", aliases, even insteadof, in different places, times, universes, etc. Including, but not limited to:
trait SpectacularStuff1 { use TheErrorOfYourWays{ TheErrorOfYourWays::booboo as booboo1; } } trait SpectacularStuff2 { use TheErrorOfYourWays{ TheErrorOfYourWays::booboo as booboo2; } } class DoSomethingSpectacular { use SpectacularStuff1, SpectacularStuff2 { /* Tried separately, but included here for brevity's sake */ SpectacularStuff1::booboo as booboo3; SpectacularStuff2::booboo as booboo4; } }
AND
use TheErrorOfYourWays as Erroneous1; trait SpectacularStuff1 { use Erroneous1{ Erroneous1::booboo as booboo1; } } use TheErrorOfYourWays as Erroneous2; trait SpectacularStuff2 { use Erroneous2{ Erroneous2::booboo as booboo2; } }
I understand that:
- I can change TheErrorOfYourWays to a class and make booboo() static but I would like to learn about this specific trait behaviour.
- I can remove TheErrorOfYourWays from the traits and use it in the class, but that's hardly "self-contained" then. Everytime I use the traits I have to remember to use TheErrorOfYourWays in the class even if I don't call booboo() directly from the class. Sounds dangerous.
- I have probably made some rookie syntax error or failed to understand aliasing on a profound level. If so, please... explain... slowly...
- There is probably a better way to do this. If so, please... explain... slowly...
- I may be prematurely enthusiastic and PHP doesn't do this yet. Let me down gently.
Thanks!
-
Just Plain High over 10 yearsAs mentioned in the question, I did but that also produced an error. Please provide an example of working code because it may be that I didn't implement it correctly. Thanks :)
-
Just Plain High over 10 yearsHmmm... well, thanks for teaching me about the proper use of insteadof. I did not know that :). But this still doesn't resolve the conflict at the trait level. It requires that I know which traits and classes call the same traits and could result in a very long list of insteadof's. Or am I still missing something?
-
Shankar Narayana Damodaran over 10 yearsI think that is how it goes (you need a long list :( ), Btw did you have a look at the
example #5 : conflict resolution
of the link i provided.? -
Just Plain High over 10 yearsI did see #5 and I tried it but it didn't give me the result I was looking for. I scrutinized the manual before coming here, trust me ;) This "long list" news saddens me :(.
-
Just Plain High over 10 yearsMuch appreciated :) Thank you very much for the help!
-
Admin over 9 yearsInteresting... just have to remember to always use A ;-)