Hey all I've posted before about adding the ability to do dynamic decorators before. I think I have come up with a method to do so in core.
Basically, the problem is that I can't create a decorator for a class at all. I would have to extend that class (with all of the coupling issues that brings). I can create a decorator for interfaces, but I'd need to list proxy methods for each and every interface combination in each decorator. This leads to tons of boilerplate issues. For example: class CachableFooDecorator implements foo { protected $parent; public function __construct(Foo $obj) { $this->parent = $obj; } public function __call($method, $args) { return call_user_func_array(array($this->parent, $method), $args); } public function method1($a, $b) { return $this->parent->method1($a, $b); } public function method2($a) { if (!$this->hasCache('method2', $a)) { $ret = $this->parent->method2($a); $this->setCache('method2', $a, $ret); } return $this->getCache('method2', $a); } } That's a lot of boilerplate for each possible iteration. This is one reason people like traits so much, as it's easier to just do automated copy/paste than use the proper patterns. So, I've wanted to add a dynamic way of being able to decorate classes at the core level. So you'd declare the class in a special way and it would handle that boilerplate for you. I've come up with a method to do so. Basically, I created a class SplDecorator which looks like this: class SplDecorator { private $parent; public function __construct($obj) { $this->parent = $obj; } public function __call($method, $args) { return call_user_func_array(array($this->parent, $method), $args); } public function getDecoratedObject() { return $this->parent; } } The other difference, is there's an object creation handler which adds the parent's class entry to the current instances interface list. Basically: Z_OBJCE_P(this)->interfaces = safe_realloc(Z_OBJCE_P(object)->interfaces, Z_OBJCE_P(object)->num_interfaces + 1, sizeof(zend_class_entry), 0); Z_OPJCE_P(object)->interfaces[Z_OBJCE_P(object)->num_interfaces] = Z_OBJCE_P(parent); Z_OBJCE_P(object)->num_interfaces++; Now, the internal instanceof function is recursive, so it will return true when tested against this class list. So, example code like: class Foo {} class Bar extends SplDecorator {} $b = new Bar(new Foo); var_dump($b instanceof Foo); // true It also works with type hints: function test(Foo $f) {} test($b); Now, there's a lot more to do (property cascading, interface validation, etc), but the initial proof-of-concept is there. I have it working locally, I'll push it to github on my branch in a day or two so that you can play around with it... What do you think? Is this a route that I should continue down? Or is there something fundamental that I'm missing here? I know that Reflection, get_interfaces(), etc would need to be updated to account for this. Thoughts? Anthony