21

Simple question, is it possible to dynamically add traits to a php class in runtime without using eval?

Thomas Lauria
  • 858
  • 1
  • 7
  • 15
  • 2
    Please read this: http://stackoverflow.com/questions/10461965/dynamicly-creating-class-with-trait-binding and this: http://blog.ircmaxell.com/2011/07/are-traits-new-eval.html – Mário Rodrigues Jan 16 '13 at 09:32
  • 8
    This really sounds like a bad code smell – Mark Baker Jan 16 '13 at 09:36
  • I have a php framework with dependency injection. My Idea was to put some reusable functionality as traits directly to the class configuration. The way around is, to create a subclass using the traits, and configure the DI to use the subclass instead the baseclass. I wanted to avoid creating the subclass for adding the traits. – Thomas Lauria Jan 16 '13 at 11:09
  • What's wrong in creating a subclass? Extending the base class is exactly what you seem to want to achieve here. – aalaap Feb 01 '18 at 04:06

2 Answers2

16

As Glavic said, you can't without using eval() or reflection hacks (and I'm not even sure about that).

But it's very unlikely you really need to.

You can achieve a lot with dynamic class composition (composing a class with some functionality you want into another class). That's simply a matter of putting a reference to the class with the desired functionality into a variable in the hosting class.

class SomeClassWithNeededFunctionality {}

class SomeClassThatNeedsTheFunctionalityOfTheOtherClass {
    private $serviceClass = NULL;

    public function __construct (SomeClassWithNeededFunctionality $serviceClass) {
        $this -> serviceClass = $serviceClass;
    }
}
GordonM
  • 31,179
  • 15
  • 87
  • 129
  • 3
    No reflection does not provide such a functionality. – Thomas Lauria Jan 16 '13 at 11:05
  • I remember Prestashop (a french eCommerce solution with Php) used this technique to enable core override (eval). It works, but you must consider that it will break IDE auto complete, APC cache (because the eval at runtime) etc... – Thomas Decaux Aug 25 '13 at 21:22
  • It’s possible to approximate this without using eval with a combination of reflection and the magic method __call(). But I would only recommend it for very special scenarios. For an example, see https://github.com/mbrowne/dci-php/blob/master/RolePlayer.php – Matt Browne Oct 06 '18 at 12:14
  • (Actually, the above example does make limited use of eval() just to turn the trait into a class since you can’t use traits on their own. In an earlier implentataion I just used classes in the first place so didn’t need eval(), but traits look nicer since they’re conceptually being used as dynamic traits.) – Matt Browne Oct 06 '18 at 12:17
  • @MattBrowne I'd dispute that traits are nicer than service-providing classes. You can't make assumptions in a trait about the hosting class without risking causing epic breakage if the class that uses the trait doesn't meet those expectations – GordonM Oct 08 '18 at 11:07
  • @GordonM I agree that that’s a potential issue with traits. I was just talking about the syntax - if you have decided you want to approximate dynamic traits, it’s more readable if the code reflects that. In DCI (which is what I implemented this for) there’s the concept of a role-object contract, which specifies requirements that an object must meet to play that role (a role is similar to a trait). Without such contracts, using traits willy-nilly is indeed treading in dangerous territory... – Matt Browne Oct 08 '18 at 14:01
0

No.

p.s. you can have them in standalone files, and use include() ?

Glavić
  • 42,781
  • 13
  • 77
  • 107