Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:62162 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 66140 invoked from network); 14 Aug 2012 23:18:51 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 14 Aug 2012 23:18:51 -0000 Authentication-Results: pb1.pair.com header.from=ralph@ralphschindler.com; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=ralph@ralphschindler.com; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain ralphschindler.com from 209.85.214.170 cause and error) X-PHP-List-Original-Sender: ralph@ralphschindler.com X-Host-Fingerprint: 209.85.214.170 mail-ob0-f170.google.com Received: from [209.85.214.170] ([209.85.214.170:56234] helo=mail-ob0-f170.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 7D/53-47147-9DCDA205 for ; Tue, 14 Aug 2012 19:18:50 -0400 Received: by obbwc18 with SMTP id wc18so1408590obb.29 for ; Tue, 14 Aug 2012 16:18:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding :x-gm-message-state; bh=quTcZioJ9ChlUatow7N8OEyjHjy9c/0P5LgWFKxedeM=; b=l0ZQC6HCe8joqhdeI2GU4JIU6ayOSNy73K/Tty3F0qqsn91EmomMRBOqXR+Nifo2BH KQYHK+Vl5jNeZVdEp58w/zJAsAZDhanFHdBtr75qHfuA2ZOR9T38A2iWhG+QjZ3e3ppL 4vSUfsYqtRiKiGKVxEgNQXyQf99yiwN50fam9K3hXobcN9Id7MqaIi6NiSv0YeLJ5FZ5 BsknlFhb5PEO2qYn94dPWqL6jl7Reb25OOvVc6Bs8nYcmmXIxwG1/1jc4VDyFHW1uSjl K7ulg8YhvaELgvoOQPNwqMzGbiqexAhQbZAY7BzsLdHRMi9qiO5caZQxQmosqszVFyHj rNJA== Received: by 10.182.145.8 with SMTP id sq8mr21930855obb.50.1344986325999; Tue, 14 Aug 2012 16:18:45 -0700 (PDT) Received: from Ralphs-Mac-Pro.local (ip174-73-14-247.no.no.cox.net. [174.73.14.247]) by mx.google.com with ESMTPS id bp7sm4005493obc.12.2012.08.14.16.18.45 (version=SSLv3 cipher=OTHER); Tue, 14 Aug 2012 16:18:45 -0700 (PDT) Message-ID: <502ADCD4.6020307@ralphschindler.com> Date: Tue, 14 Aug 2012 18:18:44 -0500 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:14.0) Gecko/20120713 Thunderbird/14.0 MIME-Version: 1.0 To: Anthony Ferrara CC: internals@lists.php.net References: <502A81AD.1070303@ralphschindler.com> <502AA750.1060406@ralphschindler.com> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Gm-Message-State: ALoCoQnvjFZ2fQpLG02DC54ecu/9s7nWbCt/heTfQazkflYW8QggbD2T4zzirWwLw865zKNJ577x Subject: Re: [PHP-DEV] Decorators Revisited From: ralph@ralphschindler.com (Ralph Schindler) 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