On 3 December 2010 12:53, <presid...@basnetworks.net> wrote: >> On 2 December 2010 13:51, <presid...@basnetworks.net> wrote: >>>> 2010/12/1 Richard Quadling <rquadl...@gmail.com> >>>> >>>>> On 1 December 2010 09:22, Stas Malyshev <smalys...@sugarcrm.com> >>>>> 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 = NULL. >>> >>> >>> Thats simple then, when isset is invoked, call the get method, and if it >>> 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 = false){ >> static $lastValue; >> >> if (!$isset) { >> // Generate the new value and assign it to $lastValue >> } >> >> return $lastValue; >> } > > The major issue I see here, is that a property should not be generating a > value in an unpredictable way. In the example above, you indicate that > the value could change just by calling the get method. 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. > The value of a property (as viewed from the outside of the class) should > never, ever change solely by a call to a getter method. > > Basically what this means, is that two subsequent calls to a get method of > a property should ALWAYS return the same value. I 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 not > work as desired. > > If you need to generate and return a random or similar value, that should > be done as a method. See the MSDN article "Choosing Between Properties > 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. If you call isset() on a property, you are asking > "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 complicates > 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. -- Richard Quadling Twitter : EE : Zend @RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php