Ralph, On Tue, Aug 14, 2012 at 12:49 PM, Ralph Schindler <ra...@ralphschindler.com>wrote:
> In general, I think it would be nice to have something that does this for > you, but I am not necessarily a fan of changing the meaning of instanceof. > > > 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. >> > > Couldn't a dynamic trait be a better? It would work like this: > > trait SplDynamicProxyTrait { > > protected $proxyObject; > > // enumerate all public method with the following: > public function $name($signature) { > return $this->proxyObject::$name($**signature); > } > > } > > usage would then be the following: > > class MyDecorator implements FooInterface { > use SplDynamicProxyTrait; // compile time "code generation" > public function __construct(Foo $foo) { > $this->proxyObject = $foo; > } > // override trait > > public function method2($a) { > if (!$this->hasCache('method2', $a)) { > $ret = $this->proxyObject->method2($**a); > > $this->setCache('method2', $a, $ret); > } > return $this->getCache('method2', $a); > } > } > > > 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); >> > > These would all still work, instanceof would actually be an instanceof > though. > > > Now, there's a lot more to do (property cascading, interface validation, >> etc), but the initial proof-of-concept is there. >> > > 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? >> > > In the above scenario, we've reused traits and we haven't broken > instanceof or the liskov principle (which basically your implementation > does since SplDectorator bypasses all method signature checking until > runtime). > > Thoughts? :) > > -ralph Well, I like it at first glance. There are two main problems that I see with it: 1. It still requires a separate decorator class for every combination of interfaces you want to decorate. So, for example if you wanted to decorate a Foo interface, but sometimes it's used with Iterator as well. Then you'd need two classes. If there was a third interface, you'd need four separate classes. Same problem with class bloat minus a lot of the boilerplate. 2. It's still not possible to decorate a typed class. So I can't decorate PDO without first extending PDO with a user-supplied interface. And I don't understand how this breaks LSP... We're not extending the decorated class. In fact, we can add construct time checking to ensure the original interfaces are all enforced (and even go a step further and ensure that all method signatures are the same that are overridden). LSP is not a compile time concern, it's a purely runtime concern (in PHP at least). The fact that interface contracts are enforced at compile time is nice, but it's not a strict necessity to enforcing LSP. Anthony