Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:65116 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 2375 invoked from network); 23 Jan 2013 17:00:40 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 23 Jan 2013 17:00:40 -0000 Authentication-Results: pb1.pair.com smtp.mail=cpriest@zerocue.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=cpriest@zerocue.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain zerocue.com designates 67.200.53.250 as permitted sender) X-PHP-List-Original-Sender: cpriest@zerocue.com X-Host-Fingerprint: 67.200.53.250 mail.zerocue.com Received: from [67.200.53.250] ([67.200.53.250:46352] helo=mail.zerocue.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id CB/80-30997-83710015 for ; Wed, 23 Jan 2013 12:00:40 -0500 Received: from [172.17.0.122] (unknown [70.112.216.188]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by mail.zerocue.com (Postfix) with ESMTPSA id 2D1381203A3; Wed, 23 Jan 2013 17:00:37 +0000 (UTC) Message-ID: <5100172C.8040903@zerocue.com> Date: Wed, 23 Jan 2013 11:00:28 -0600 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20130107 Thunderbird/17.0.2 MIME-Version: 1.0 To: Sherif Ramadan CC: Anthony Ferrara , PHP Developers Mailing List References: <50F840F4.7080704@zerocue.com> <50FE7579.1010409@zerocue.com> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [PHP-DEV] [VOTE] Property Accessors for 5.5 From: cpriest@zerocue.com (Clint Priest) On 1/23/2013 8:31 AM, Sherif Ramadan wrote: >> Except that everything that's proposed here is possible today with __get, >> __set, __isset and __unset. So already today you can't assume that a >> property is a "variable". In fact, you could build something like this >> using __get, etc extremely dirty: >> >> class Foo { >> public function __get($name) { >> $method = 'get' . ucfirst($name); >> if (method_exists($this, $method)) { >> return $this->method(); >> } >> return $this->$name; // public properties >> } >> public function __set($name, $value) { >> $method = 'set' . ucfirst($name); >> if (method_exists($this, $method)) { >> return $this->method($value); >> } >> return $this->$name = $value; // public properties >> } >> } >> >> The difference in functionality that this provides is the ability to >> custom-scope getters and setters. And it's a LOT cleaner... Just a reminder on that cleanliness... Symfony: 3,805 functions that are getters or setters, Zend Framework: 4,080 functions that are getters or setters, not even counting what is being done with __get(). > This is not true. Magic getters and setters make a distinction that > accessors do not. That distinction is that they can only work on > inaccessible properties. Accessors offer no such distinction. They are > explicitly defined and as such their properties are not magical even though > they provide somewhat magical characteristics. > > When you use var_dump to debug the property of an object, or the object > itself, for example, you would expect that whatever value is returned for > that property is either stored in memory somewhere or is the result of a > magic getter. Now, if it is the result of a magic getter there is no > confusion between whether this is an actual property or magic getter, > because a look at var_dump of that object tells us the whole story. Actually you could say that last sentence is precisely opposite of the truth in that a var_dump() will *never* expose properties that are available via a magic __get() therefore a var_dump() already mis-leads the developer because there can be properties that can be retrieved which are not shown by a simple var_dump(). > With accessors you now make the case that the property can be the result of > any computation and as such var_dump only reveals the underlying storage > unit and has no awareness of any computation. > > class foo { > public $bar { > get() { return 'baz'; } > } > } > > var_dump(json_encode(new foo),new foo, (new foo)->bar); > > // gives us > string(12) "{"bar":null}" > object(foo)#1 (1) { > ["bar"]=> > NULL > } > string(3) "baz" > > > There's a subtle difference here that's not obvious at first. The > difference is that we have no way of knowing whether "bar" is the result of > an accessor or a an actual property without closely examining the code. > There's no easy way to debug who went wrong when this causes a problem. If > the property is now acting as a method we have to start treating it like a > method in order to debug it. That could mean backtraces, exception > handling, and a variety of other things that I really find weird to have to > do with an a property. > > > Now, let's examine the alternative. Using magic methods... > > class foo { > private $bar; > public function __get($name) { > if ($name == 'bar') { > return 'baz'; > } > } > } > > var_dump(json_encode(new foo),new foo, (new foo)->bar); > > string(2) "{}" > object(foo)#1 (1) { > ["bar":"foo":private]=> > NULL > } > string(3) "baz" There had been very recent talk of having an accessor output something to the effect of: object(foo)#1 (1) { ["bar":"foo":accessor]=> NULL } I would actually favor the idea that nothing can see the property value except the accessor and this would mean that a var_dump() would call the accessor. By having var_dump() read the value of the underlying property directly it really violates the entire idea of an accessor. Every other language that implements accessors (and it's most modern languages) there is no actual underlying property. This is the way 1.1 originally proposed it, but that was not what people wanted, they did not want to have to declare a backing property of their own and so it was changed. The result of the current RFC is a result of the endless discussion that was had on this topic. It's really not appropriate to vote against something if you did not make your voice heard when discussions of some aspect were happening. > At least here we know that "bar" is undoubtedly a private property so > whatever we got from (new foo)->bar must be the result of a magic getter. > There's only one place to look for that (in the magic method). With an > accessor I could easily create a situation where a bug manifests itself > anywhere in the code and not necessarily in the accessor itself that > accessor effectively becomes a method that does computation rather than > handling mere storage and retrieval. > > I really really feel this is a way to give users lots of rope to hang > themselves with and at the cost of added complexity. I'm just not sure I > buy it. Sorry. I'm not sure what kind of rope you're talking about here, if an error occurs in an accessor it's stack trace clearly indicates where it is occurring, even if it happened somewhere outside of an accessor but through it (like the getter calls other code where the error occurs). Unless you're talking about someone who doesn't know how to use a debugger or use the basic functionality such as stack traces, there is no lack of clarity in what has gone wrong. -- -Clint