Hey Anthony,
There's a lot here, so I'm only going to address a few things.
It sounds to me like you haven't tried to use decorators for any complex
logic. Making it type equivalent leads to very vebose code. And a PITA
I actually have used both Decorators and Proxies (it's cousin) a number
of times and some in complex situations (these are all ZF2)
http://git.io/HdRe6g (Zend\Di), http://git.io/6EGv4Q
(Zend\ServiceManager), and http://git.io/DhXDFA (Zend\Db Sql
Abstraction), all that aside ...
to write. This is one of the reasons that traits are so heralded.
Because problems that are easy to solve with decorators (in general) are
difficult to solve with PHP, so people wind up writing copy/paste
If what you're trying to do is decorate an instance of a particular
concrete type, the basic structure/foundation for creating a Decorator
(as defined by wikipedia), can be achieved in PHP with about 3 lines of
code:
class FooDecorator extends Foo {
protected $subject;
public function __construct(Foo $foo) {
$this->subject = $foo;
foreach (get_object_vars($foo) as $n => $v) {
$this->{$n} =& $foo->{$n};
}
}
}
At this point, any instance of new Foo is statefully and type equivalent
to new FooDecorator($foo). Now, you're free to add in your custom
decoration logic, overridden methods, additional methods, new
interfaces, etc. An instance of FooDecorator can be used an any place
an instance of Foo would have been used. i.e., it's bound to the Foo
context.
Let's get one thing clear here. It's not a LSP check. In that exact
example it is. But in general, it also prevents the LSP valid:
interface foo { public function bar(array $a); }
class Bar implements Foo { public function bar($a); }
That's 100% in compliance with LSP. Yet it's disallowed. The reason is
that interfaces are not primarily a LSP enforcer. They are primarily a
contract enforcer. LSP is a usual side-effect, but it's not a guarantee.
I'll give you this one.
That is an example of contravariance of method arguments, which I'd
argue should probably be allowed (if it's not that expensive to do so).
PHP does not specifically say it or define type sets, but one would
assume that "no type required" should mean "all types" which technically
might include "array".
And I don't need to resort to duck typing for it to work. All I need is
the ability to decorate at will. I'm not talking about nuking the
meaning of the interfaces (as they'd be proxied to). But more just
We're going to have to disagree on the "meaning of interfaces".
Interfaces are a foundational element of a class based type hierarchy.
If you want Interfaces without them being in an instance type hierarchy,
I'm not sure what you call that; but it's not an Interface. The
decisions made in the PHP group around the class type system more
closely resemble those made by Java and C#.
Concerning your code snippets above.
It sounds like you want to dynamically build classes and methods, on the
fly, or you want a magical subclass that is free from the current rules
of is_a, instanceof, etc.
Put another way, some developer somewhere built a system and has a
method signature like
class Controller {
public function dispatch(Dispatchable $dispatchable) { ... }
}
and they have provided the Dispatchable interface. But you want to take
any old object that does not implement Dispatchable and be able to
modify it on the fly to bypass his type check in his type check in the
method signature of his dispatch().
to solve this problem. I'm talking about runtime composability of
functionality. Not compile time. I want to be able to construct my
objects from other interactions (like database settings), not just be
limited to having to copy/paste for everything.
That's just crazy talk right there! ;)
composing functionality != composing types
In PHP (currently, as anything could change), is_a, instanceof and
method type signatures are used by people who believe in a class based
type inheritance system and the system of checks built around that.
Your proposal attempts to change that such that special types can be
exempt from the type checking rules for the purpose of a particular
pattern (Decorator). I've personally never had a problems with
decorating, so it is hard for me to envision the system you are building
where Decorators are a problem.
-ralph
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php