Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:62157 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 45299 invoked from network); 14 Aug 2012 19:30:29 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 14 Aug 2012 19:30:29 -0000 Authentication-Results: pb1.pair.com smtp.mail=ralph@ralphschindler.com; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=ralph@ralphschindler.com; sender-id=unknown Received-SPF: error (pb1.pair.com: domain ralphschindler.com from 209.85.216.42 cause and error) X-PHP-List-Original-Sender: ralph@ralphschindler.com X-Host-Fingerprint: 209.85.216.42 mail-qa0-f42.google.com Received: from [209.85.216.42] ([209.85.216.42:63543] helo=mail-qa0-f42.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 9B/F1-00812-457AA205 for ; Tue, 14 Aug 2012 15:30:29 -0400 Received: by qaeb19 with SMTP id b19so4005906qae.8 for ; Tue, 14 Aug 2012 12:30:26 -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=5yRdBPBrgV5de23JYKvkhlAYORgtBzqntBtqcmhUsI0=; b=FYbPNLsD6gPhElWoRueQmgZpGuCUlLPeaKdlmr23k2XWaxCXUQ/Nqqk/66Tozqc9rb +MdxjkLQMGhG9mnyYhYceHSnM1GTC6XhG88NKLduVaHY2b1stPdFMac8VIS/bMbR6bHu XuNOpVncILMUcpUDjs3baEbL5Yn0+hq496LhilOfCzXmKPAllo6yzTAx6lhUb9Or+KKc JI/d9avkj8XHv8EafwuuDhjtXtAWa0Gfsrm3dEmMNERjD8U9D9Si+3lqKiPzEbEWnvwg ZasB/Q+Hb1Dz/vuVkXL6l3sI5JqeaJMEBFvmoGqdhnA/QQZ99eEw76JP2MMlGuo5isB5 Fc9A== Received: by 10.60.6.73 with SMTP id y9mr27624569oey.17.1344972626254; Tue, 14 Aug 2012 12:30:26 -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 hz6sm3529116obb.1.2012.08.14.12.30.25 (version=SSLv3 cipher=OTHER); Tue, 14 Aug 2012 12:30:25 -0700 (PDT) Message-ID: <502AA750.1060406@ralphschindler.com> Date: Tue, 14 Aug 2012 14:30:24 -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> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Gm-Message-State: ALoCoQkdkARSW4VC9lM6+j60JWe2I8yLTTor8/tCpYfR1sge+BWi8pqYboUwztxymV9ZYSrajt8w Subject: Re: [PHP-DEV] Decorators Revisited From: ralph@ralphschindler.com (Ralph Schindler) > 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. You'd need a class anyway for your custom logic to live, that custom logic is the reason you want a Proxy in the first place. In your example, you want to proxy and object, but for one of the method, presumable an expensive method, you want to be able to cache the output before needing to go to the actual object. If Iterator was required for the Foo contract/interface, that would have bee in the Foo interface definition as well. Even in your example, you still have this: class Bar extends SplDecorator {} But what you are really intending is: class Bar extends MagicToMakeThisActLikeAnyType {} Ultimately, the instance you are decorating and decorator itself need to be "type equivalent". Meaning the generally accepted understanding of is_a() and instanceof constructs need to also apply to the decorator object just as it would any other object. > 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. I don't follow. What do you mean by a "typed class"? > 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 That is where we are going to differ. Simply because your object responds to all the same methods of, for example, the FooInterface, does not make it a FooInterface subtype. It just means that in the "duck typing" sense of the phrase, it can act like a FooInterface for people that are not necessarily concerned that it's actually not is_a() FooInterface. In other words, yes, it will pass all sorts of method_exists() checks, but it'd never be able to pass an instanceof, is_a, or is_subclass_of() check on FooInterface. > 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 When I say "compile time" I mean PHP's compile time, in so far as PHP is a compile and execute style interpreted language. The following script demonstrates the enforcement of subtype expectations: That will produce: PHP Fatal error: Declaration of Bar::bar() must be compatible with that of Foo::bar() in ... That is an LSP check, and it is done at PHP's compile time. The rule "Preconditions cannot be strengthened in a subtype" is violated since you attempted to add an argument to the bar() method of the Foo contract. > least). The fact that interface contracts are enforced at compile time > is nice, but it's not a strict necessity to enforcing LSP. Why not do it at compile time? When php is building up its class entry table, it should be in its best interest to not have incomplete or invalid types in there, right? But, I do support getting more duck typing facilities in PHP, and reusing traits in places where we need more compiler assisted copy/paste when boilerplate is cumbersome. -ralph