Newsgroups: php.internals,php.internals Path: news.php.net Xref: news.php.net php.internals:17641 php.internals:17642 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 95740 invoked by uid 1010); 9 Aug 2005 01:39:31 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 95725 invoked from network); 9 Aug 2005 01:39:31 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 9 Aug 2005 01:39:31 -0000 X-Host-Fingerprint: 68.112.247.235 68-112-247-235.static.oxfr.ma.charter.com Received: from ([68.112.247.235:29022] helo=localhost.localdomain) by pb1.pair.com (ecelerity 2.0 beta r(6323M)) with SMTP id F6/BA-04646-15908F24 for ; Mon, 08 Aug 2005 21:39:29 -0400 To: internals@lists.php.net,Derick Rethans Message-ID: <42F80940.7080209@128kb.com> Date: Mon, 08 Aug 2005 21:39:12 -0400 User-Agent: Mozilla Thunderbird 1.0 (Windows/20041206) X-Accept-Language: en-us, en MIME-Version: 1.0 CC: PHP Developers Mailing List , Jan Borsodi , Raymond Bosman , Frederik Holljen , Tobias Schlitt References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Posted-By: 68.112.247.235 Subject: Re: Property Overloading RFC From: jhannus@128kb.com (Justin Hannus) The way ActionScript 2.0 solves this is with set and get keywords on function declarations. Any class can contain as many setter/getters as they need,. Since we dont want to introduce any new keywords how about something similar with __set and __get? _fooProp = $val; // $_fooProp is read only } function __set barProp($val) { // logic to set barProp... } function __get barProp($val) { // logic to get barProp... } } ?> To allow for BC, if there is no identifier after the __set/__get then the existing rules apply. -Justin Derick Rethans wrote: > Hello! > > we're finding some problems with property overloading (__get() and > __set()). Here is an RFC describing what we'd like to see changed. > Please comment on this. > > > Introduction: > PHP currently supports property overloading with the magic functions __get() > and __set(). Those methods are called when the code "echo $object->a" or > "$object->a = 42" are executed and the property "a" is not declared in the > class. The magic methods are responsibly for: > - checking if the property actually "exists" > - setting the value or returning the value depending on the action > > Problems: > 1. There is no way to document the 'virtual' properties with any of the existing > documentation tools (such as phpdoc and doxygen) > 2. There is no way how the magic methods know if a specific 'virtual' property > exists or not as those properties are not declared usually - unless you > define an array with property names as a class constant (which is not > allowed either). > 3. There is no way for the magic methods to return a meaningfull error when a > property doesn't "exist". Of course it is possible to throw an error with > "trigger_error" or "throw" in case a property doesn't "exist" in a specific > class, but the file and line numbers would not match the actually get/set > action. debug_backtrace() can be used to retrieve the correct file and line, > but as you have to do this for every class where you want to use setters and > getters *and* you have to implement your own error message rendering > function this is not really a suitable option either. > > > Solutions: > - For problem 1. we can introduce a keyword (or use an existing one) to define > that it is a virtual property ('abstract' or 'virtual' come to mind). When > declaring it like this it's easy to document, and we can also implement > visibility for those virtual properties. Marcus already has a patch for > this somewhere, which uses the "abstract" keyword for this purpose: > > class Base > { > /** > * @var int Contains all X > */ > abstract public $x = 1; > > /** > * @var int Contains all Y > */ > abstract protected $y = 2; > > // abstract private $z = 3; abstract properties cannot be private > } > ?> > > - In combination to the introduced keyword we need an easy way to check if a > passed property name is declared in the class as 'virtual'. Currently (with > the 'abstract' keyword properly implemented) you'd have to do: > > class Base > { > abstract public $x = 1; > > function __get($name) > { > try { > $prop = new ReflectionProperty('Base', $name); > if ( !$prop->isAbstract() ) { > /* throw error */ > } > } catch ($e) { > /* throw error */ > } > } > } > > $b = new Base(); > echo $b->foo; > ?> > > This is ofcourse overly complicated. A better workable solution would be - > without breaking BC (suggestions for syntax here are very welcome): > > class Base > { > abstract public $x = 1; > > function __get($name) > { > if (!self::isVirtual($name))) { > /* throw error */ > } > } > } > > $b = new Base(); > echo $b->foo; > ?> > > - Problem 3 can be solved by: > * allowing optional by-ref parameters to the __set > and __get function, so that their signatures become: > > function __set($name, $value [, &$error] ) > function __get($name [, &$error] ) > > If the parameter is not given things behave just like they do now -> __set > and __get can not throw meaningful errors with the correct file/line of the > conflicting statement > > If the parameter is used in the function's declaration and is set to > "false" when the __set or __get function returns, the engine can throw an > error on the assignment line with the correct file/line combination. If > it's set to "true" (or "null") then the engine should not throw any error. > > * Use a different __set and __get function for 'abstract' properties, then > the engine can already determine if you're doing something wrong before > executing the __set and __get methods. > > > regards, > Derick >