This started out as I love PHP traits! I'm going to use them everywhere! ^_^ and now it has turned into a Thought 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 (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:

  1. 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.
  2. No having to edit classes and traits on the fly when I do something "adventurous" and discover I have inadvertently created a conflict.
  3. Seemed like a good idea at the time.

What I have tried:

  1. The PHP Manual.
  2. The Google.
  3. Stackoverflow: This Question
  4. Found this but I am using PHP version 5.5.1. It's fixed, right? Right?
  5. 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:

  1. I can change TheErrorOfYourWays to a class and make booboo() static but I would like to learn about this specific trait behaviour.
  2. 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.
  3. I have probably made some rookie syntax error or failed to understand aliasing on a profound level. If so, please... explain... slowly...
  4. There is probably a better way to do this. If so, please... explain... slowly...
  5. I may be prematurely enthusiastic and PHP doesn't do this yet. Let me down gently.

Thanks!

Recommended Answers

All 6 Replies

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?

No having to edit classes and traits on the fly when I do something "adventurous" and discover I have inadvertently created a conflict.

I haven't tried it yet, but the manual states that you need to resolve your conflicts by using as and/or insteadof. This is not something that the interpreter can do for you, so you're limited to doing this manually.

Thanks pritaeas :) I read the manual :P.

insteadof only works in the calling class and if you have very complicated inheritance, it would be a very complicated list of insteadof(s) - actually, unusable.

What I thought was, if I want to create self-contained traits, then I need to resolve the conflict in the trait using as but this does not (surprisingly) work (examples provided in the questions). So now I'm wondering if I did it right... Could you please provide a sample of code? Much obliged :)

Could you please provide a sample of code

When I get some time, I'll see if I can make any sense of it. Althoug I don't think I've got 5.5.1 installed anywhere.

You can use insteadof to declare the first trait, then go with as, example:

trait TheErrorOfYourWays{
   public function booboo(){
       echo 'You had a booboo :(';
   }
}
trait SpectacularStuff1 {
    use TheErrorOfYourWays; 
}

trait SpectacularStuff2 {
    use TheErrorOfYourWays;
}

trait SpectacularStuff3 {
    use TheErrorOfYourWays;
}

class DoSomethingSpectacular {
        use SpectacularStuff1, SpectacularStuff2, SpectacularStuff3 {
            SpectacularStuff1::booboo insteadof SpectacularStuff2, SpectacularStuff3;
            SpectacularStuff2::booboo as booboo2;
            SpectacularStuff3::booboo as booboo3;
        }
    }

$do = new DoSomethingSpectacular;
$do->booboo();
$do->booboo2();
$do->booboo3();

Live sandbox: http://sandbox.onlinephpfunctions.com/code/8893d9672a02cf0ceefafe792d3159ce3bf2935e

commented: You're good :) +14
Member Avatar for diafol

<aside>So, since 5.4! Completely missed it. Thanks Gaetane +1</aside>

Always a pleasure, @diafol ;)

@cereal, I am aware of this approach (as mentioned above) but with complicated inheritance this would make traits unusable. Happily (or rather, unhappily) I am not the only one with this issue and it is a reported bug

:(

I upgraded from 5.5.1 to 5.5.6 just to make sure and it is... still a bug...

:'(

Marking as "mystery solved!"

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.