On Fri, Dec 26, 2008 at 6:53 PM, Larry Garfield <larry@xxxxxxxxxxxxxxxx>wrote: > Excuse me a moment while I delve into complex OO. :-) > > I have an object to which I want to add behavior (methods). I cannot use > inheritance here because the object is already of a type or subtype (vis, I > am > already using inheritance for something else), and because I want to be > able > to add multiple types of behavior at runtime. The normal OO response to > this > situation is the Decorator pattern. > > -------------------- > > interface F { > function doStuff(); > } > > class Foo { > function doStuff() { ... } > } > > class Decorator implements F { > protected $foo; > > function __construct(Foo $foo) { > $this->foo = $foo; > } > > function doStuff() { > $this->foo->doStuff(); > } > } > > class Bar extends Decorator { > function doThings() { ... } > } > > $f = new Foo(); > > $b = new Bar($f); > $b->doStuff(); > $b->doThings(); > > -------------------- > > OK, great, that's wonderful. You can also nest such decorators > indefinitely, > provided that they only override methods from Foo and change its behavior, > then pass on up the chain. Neat. What you cannot do, however, is nest > decorators that have public methods. That is: > > -------------------- > > class Baz extends Decorator { > function doOtherThings(); > } > > $f = new Baz(new Bar(new Foo)); > $f->doOtherThings(); // Works. > $f->doStuff(); // Works. > $f->doThings(); // Fail. > > -------------------- > > Now, PHP does have a loophole around this problem in the form of __call(). > Specifically, instead of Decorator wrapping each method of F/Foo directly > it > implements __call(): > > -------------------- > class Decorator { > protected $foo; > > function __construct(Foo $foo) { > $this->foo = $foo; > } > > function __call($method, $args) { > return call_user_func_array(array($this->foo, $method), $args); > } > } > -------------------- > > That should work and allow the code snippet above to run, but it has two > significant problems: > > 1) Because Decorator does not directly implement F, you cannot use type > hinting. > > 2) __call() and call_user_func_array() are both fairly slow operations, and > stacking them then becomes a nightmare for performance. > > #1 can largely be solved by both directly implementing F *and* implementing > __call(), but we're still left with the performance problems of #2. While > for > some uses cases that is OK, it can add up to unpleasant microseconds lost. > > Can anyone suggest an alternate solution that has less of a performance > hit? the main drawback to decoration vs inheritance is the fact that code is not essentially 'written for you', which results in lots of boilerplate code in decorators, in my experience. what that amounts to, is if you have 10 methods, whereby you only want to alter one of them in a decorator, then w/ decoration youve got 9 additional methods of crappy boilerplate code to write, that you wouldnt have to when extending instead. what is really irritating about the php __call() implementation is that interfaces are not implemented by it. i think this is pretty silly (there may be a solid reason the internals people could mention). what i mean is, intuitively, i would expect class A implements B { public function __call() {} } to work, no matter what B declares. but it doesnt, WEAK, *cough* *cough*.. *sigh* sadly, i think the best solution is just to add bolierplate code in your decorators, such that deocration methods explicitly implement the interrface w/ each successive layer, and not incur the performance overhead of __call(). essentially this is what the language would do for you when extending something. i rarely put methods all on one line elsewhere, but when decorating ill just end up doing something like this /* these are here just to implement interface F */ function doStuff() { return $this->doStuff(); } another alternative is to really buy into the whole 'dynamic' thing, and forget about the interface, roll w/ __call() and take the performance hit, which is more akin to something like youd see in javascript. personally i like to use a medly of the two. i never did much with it, but i suspect C++ templates make decoration nearly as simple as inheritence, and avoid performace overhead of something like __call(). which brings me to the third option, only really for the truely brave php programmer. templating php w/ php; its often done in code generation systems, like propel and other orm's, but basically, you'd have a template w/ skeletons for all the methods and then youd have to run some sort of generation script in order to create concreate classes for actual use. esoteric, and perhaps a little ugly (editors dont really work 'right' when templating php w/ php =/), but the technique is very powerful. to summarize, using your example above, i would most liely add doThings() to Baz, or create another decoration interface for doThings() if you plan on using the Bar implementation of doThings() in many places, interface G { function doThings(); } class Bar extends Decorator implements G { function doThings() { // concreate implementation } } class Baz implements F, G { // recycle Bar::doThings() public function doThings() { return $this->foo->doThings(); } public function doOtherThings() {} } i appologize if this response is long winded, but im a big fan of the decorator, and ive actually got some pretty slick code in production in the photobucket code that uses the decorator pattern :D it took about 2 months to code, and i leraned a lot about some of the practical aspects of decroration, specifically within the realm of php. i know i repeated a few things there, but i felt it neccessary to better explain myself. -nathan