Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:50841 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 60798 invoked from network); 3 Dec 2010 15:25:13 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 3 Dec 2010 15:25:13 -0000 Authentication-Results: pb1.pair.com header.from=rquadling@gmail.com; sender-id=pass; domainkeys=bad Authentication-Results: pb1.pair.com smtp.mail=rquadling@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.216.177 as permitted sender) DomainKey-Status: bad X-DomainKeys: Ecelerity dk_validate implementing draft-delany-domainkeys-base-01 X-PHP-List-Original-Sender: rquadling@gmail.com X-Host-Fingerprint: 209.85.216.177 mail-qy0-f177.google.com Received: from [209.85.216.177] ([209.85.216.177:62257] helo=mail-qy0-f177.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 1B/C0-53679-8DB09FC4 for ; Fri, 03 Dec 2010 10:25:13 -0500 Received: by qyk27 with SMTP id 27so9918810qyk.8 for ; Fri, 03 Dec 2010 07:25:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:mime-version:received:reply-to :in-reply-to:references:from:date:message-id:subject:to:cc :content-type:content-transfer-encoding; bh=5n6w8laGDjm0e7gLsuIbjDreCSxrRgyl6jZI5z3iDRs=; b=B6H8SsZE33cUvwr9sWhPff88bmFHxwqXE6O15ZJTdje5KS8rZvV2Aj14gdtxbJlS8R KEncaOGY5on3FZ3RCU+b6UGKgxvQQGH91FPc+DNohP6WxTLwt5lgLnEPJ44nkEGC2idK TU3LSznOZHODbt0zmOiosb4Gxn3YfMbYUzH4Y= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:reply-to:in-reply-to:references:from:date:message-id :subject:to:cc:content-type:content-transfer-encoding; b=m3CQK9aYBxqvY326L4opLwe99yl8N3DJyTlb5wwQTBe/M5s4rUy6nkLQ8MTGXhUgkS HmArx43glr3n9hkdLQHbU8/06fWkBSJWe8p3O1ohtxni7vEMmFnLt0bWYqcgxpPlSh7A T6ytleHXeGsUG5Trjh9wGPpfgoV5z0CKv1qK4= Received: by 10.229.95.211 with SMTP id e19mr1375358qcn.139.1291389909890; Fri, 03 Dec 2010 07:25:09 -0800 (PST) MIME-Version: 1.0 Received: by 10.229.100.130 with HTTP; Fri, 3 Dec 2010 07:24:48 -0800 (PST) Reply-To: RQuadling@googlemail.com In-Reply-To: <4814e263cbd2b09767ca16908dd4ee01.squirrel@webmail.basnetworks.net> References: <003601cb8fd0$f6494e80$e2dbeb80$@com> <4CF3B855.5010406@sugarcrm.com> <003401cb8fee$1be39840$53aac8c0$@com> <2450924ae03481f5b1382a7f00e5743d.squirrel@webmail.basnetworks.net> <4CF50245.5020807@sugarcrm.com> <4CF5118B.2030300@sugarcrm.com> <1faa4c3db62771335db714507ac2adfa.squirrel@webmail.basnetworks.net> <4CF613EB.40200@sugarcrm.com> <8b46dd8e3e991cfe87550a9c55d9ecd8.squirrel@webmail.basnetworks.net> <4814e263cbd2b09767ca16908dd4ee01.squirrel@webmail.basnetworks.net> Date: Fri, 3 Dec 2010 15:24:48 +0000 Message-ID: To: president@basnetworks.net Cc: Eloy Bote Falcon , Stas Malyshev , "internals@lists.php.net" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] RFC: C-sharp style property get/set syntax for PHP From: rquadling@gmail.com (Richard Quadling) On 3 December 2010 12:53, wrote: >> On 2 December 2010 13:51, =C2=A0 wrote: >>>> 2010/12/1 Richard Quadling >>>> >>>>> On 1 December 2010 09:22, Stas Malyshev >>>>> wrote: >>> ... >>> >>>> Why change the expected behavior of isset? If a property has not been >>>> set >>>> then isset must return false, and that includes $foo->name =3D NULL. >>> >>> >>> Thats simple then, when isset is invoked, call the get method, and if i= t >>> returns null then isset() returns false, but otherwise returns true. >>> That >>> was likely just a small oversight on Richard's part. >> >> No, it was not an oversight. >> >> Calling the getter() in response to isset() will probably result in a >> change to the value of the property. For a property, isset() can and >> only be interested in the last value of the property, not the next >> value. >> >> As I understand things, isset() performs 2 tests. First a check to see >> if the variable exists and then to see if it has a value assigned. >> >> For a property, the first part of that equation is fairly simple - the >> property has to exist or not. >> >> The second part though is not easy. A variable will not change value >> in response to isset(), but, if isset() calls the getter(), then it >> could and probably would. Calling isset() shouldn't alter anything. > > Agreed, isset should not alter anything. > >> Having isset() call the getter() and unset() call the setter() is fine >> as long as the getter() and setter() know why they are being called. >> >> If the developer needs to supply the last value - their choice - then >> this could be implemented by caching the last value in a local scope >> static. Completely encapsulated. >> >> get($isset =3D false){ >> =C2=A0static $lastValue; >> >> =C2=A0if (!$isset) { >> =C2=A0 // Generate the new value and assign it to $lastValue >> =C2=A0} >> >> =C2=A0return $lastValue; >> } > > The major issue I see here, is that a property should not be generating a > value in an unpredictable way. =C2=A0In the example above, you indicate t= hat > the value could change just by calling the get method. =C2=A0While it is > possible to write a property that does such a thing, this is completely > incorrect and should not be actively supported by the language in any way= . > =C2=A0The value of a property (as viewed from the outside of the class) s= hould > never, ever change solely by a call to a getter method. > > Basically what this means, is that two subsequent calls to a get method o= f > a property should ALWAYS return the same value. =C2=A0I think this is the= only > scenario that we should care to support, and if the user is changing > values in a getter method, then they need to understand that isset may no= t > work as desired. > > If you need to generate and return a random or similar value, that should > be done as a method. =C2=A0See the MSDN article "Choosing Between Propert= ies > and Methods" for more details: > > http://msdn.microsoft.com/en-us/library/ms229054.aspx > > Isset should be a direct reflection of the value that is/will be returned > by the getter method. =C2=A0If you call isset() on a property, you are as= king > "if this property exists, and I access it, will I get a non-null value?". > > Not only that, an $isset parameter is ugly and cumbersome, and complicate= s > a feature that is meant to simplify a programmers life. > > Having isset and unset methods alongside the get/set methods seems > reasonable to me, for the situations that you do need to handle those > operations explicitly, but I do not think an isset/unset implementation > should be required in every case (meaning there must be a default way of > handling that functionality), or else properties will be avoided by > programmers due to being to complicated to create. > > - Dennis > > In a multiuser environment (where I do all my work), the current instance of an object may (and will probably will) contain stale data. Take something simple, say, a sales order processing system (SOP). Amongst all the data held in the system, there are 3 important properties to consider which cannot be altered by the sales order processing system. 1 - Credit Limit - can only be altered by the Sales Ledger (SL) system - in an SOP scenario, the credit limit is read-only. 2 - Account Balance - depending upon the process in the SOP, _this_ instance may or may not be able to alter this value. Order entry - readonly. Raising invoices for despatched orders (assuming no middle land "posting" mechanism between SOP and SL), then writable. 3 - On Order Total (the value of all outstanding orders) - Like the Account Balance, _this_ instance will not be the only entity capable of altering this value - many users in SOP will be creating new orders in real time. Invoice production for despatched orders will also alter this value. A fourth important value in this equation is ... 4 - Current Order Value - for the sake of argument, only _this_ instance can alter this value. Implemented as a getter() to a private variable fed by order details and order calculations - order discount, Tax/VAT, etc. The first 3 are retrieved from a cached, low TTL database request. The fourth could simply be a cached value with a write-through to the DB. This would allow the work in progress to be seen live, even though the order isn't yet finalised. This is extremely useful in realtime for features like realtime stock allocation. An important attribute of an account is the available balance. This is the normally the value that would be available if all outstanding orders were fulfilled, combined with their current balance and compared against their credit limit. In a multi-user system, any of these values could be different from one moment to the next. class Account{ public property $AvailableBalance{ get{ return $this->CreditLimit - ($this->AccountBalance - $this->OnOrder); } } } This hides the mechanics away and tells any user that the account for this order has a realtime $CreditLimit, $AccountBalance, $OnOrder and an accurate $AvailableBalance. At the beginning and end of the order entry and maybe as each line is being entered, the AvailableBalance is accessed to see if it the current order can be met financially. The Account's properties are all read-only in this scenario (I'd have 2 Account classes, one for the Sales Ledger and a subclass for everywhere else. The ability to essentially remove the setter() in a subclass would turn a read/write property into a readonly property). So, based upon this fairly simple scenario, isset() would clearly alter the value of the account's properties if it had to call the getter()s. And, in this example, no great harm would be caused by doing so. But it would certainly be an unnecessary overhead to do so. You say "While it is possible to write a property that does such a thing, this is completely incorrect and should not be actively supported by the language in any way.". How are you going to stop me from writing code that DOES generate a new and appropriate value in response to a getter() request. Surely that's the exact job of a getter()? To generate and supply a potentially new and accurate value. Not to supply some pre-hashed value which is accessible via __get() or by directly accessing a public variable (as seen in the EmployeeRecord on the MSDN link you gave - completely pointless). You may come back and say the mechanics should be ... public function getAvailableBalance() { return $this->getCreditLimit() - ($this->getAccountBalance() - $this->getOnOrder()) - $this->getOrderValue(); } with each property being retrieved by an appropriate method (as suggested in the MSDN article - computationally expensive for a property). But the nett effect is the same. The DB (probably via a cache with a low TTL) would still be hit - in fact it would need to hit as we need live data for the calculations. The end-user would have to type a few more letters and think in terms of "behaviour" rather than "attribute" in terms of accessing the value. This is the current way you'd have to write the code. If that is what you say I _should_ do, then I ask what are the benefits of using properties for me? At best, it seems like a way to allow separate docblocks and readonly/writeonly. If the getter can't return a different value then it really doesn't seem that useful. I'd expect a property to provide the value of an attribute of the object. Properties would also allow the developer to respond to requests to supply or alter the attribute and limit/allow that request. The value of a property/attribute can be different. A Clock object can have a time attribute. You can't change time (Einstein and Hawking may argue differently). So I have think in terms of retrieving the time from my clock rather than thinking in terms of a clock has a time property. The response to isset/unset can only sensibly be handed by the designer of the property. Either as additional isset()/unset() functions in the property, or as a flag to the get()/set() functions (my favourite). Richard. --=20 Richard Quadling Twitter : EE : Zend @RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY