On Wednesday, December 01, 2010 8:47:50 am presid...@basnetworks.net wrote:
> > Actually, I can even think of a concrete use case. Suppose I have an > > object that acts as a facade for a remote object over SOAP, REST, or > > whatever. It is using properties to represent attributes of a remote, > > say, insurance account. I want to know if a beneficiary has been set on > > the account. The most straightforward way to do so is > > > > if (isset($account->beneficiary)) { > > > > print $account->beneficiary->name; > > > > } > > > > If we are implementing such logic via __get(), we can do exactly that. > > > > If we are implementing it via properties, we should still be able to. > > Forcing the user to know that he needs to do it this way instead, but > > only if we're using properties rather than __get(): > > > > if ($account->hasBeneficiary()) { > > > > print $account->beneficiary->name; > > > > } > > > > is violating the principle of encapsulation as it means the user needs > > to know which of the three forms of $account->beneficiary happens to be > > in use. > > Hmm, I would have programmed it liked this: > > if ($account->beneficiary != null) { > print $account->beneficiary->name; > } > > To me, if a property is "not set", it means it does not exist and will not > be a valid property at any point in the object's lifetime. Null means > that it is a valid *possible* property, but does not currently hold any > value. This thinking is consistent with other languages. (I move between > languages on a daily basis, so consistency is key to keeping my sanity!) One certainly could implement it that way, but that would throw an E_NOTICE if you're using class members and $account->beneficiary is not set. So that makes properties an incomplete drop-in for class members. > > Thinking about properties further, actually, there's two other (related) > > considerations that always give me grief when dealing with __get: > > Reference returns and complex member variables. > > > > If I want a reference to a class member, I can very easily do this: > > > > $foo = &$bar->baz; > > > > If ->baz is accessed via __get(), then that only works if __get() is > > defined as function &__get($var) to start with. That's another > > encapsulation break. > > If baz is a property, I would imagine: > > $foo = &$bar->baz; > > would get a reference to the property itself, not a reference to the > return value of the set method. Therefore each call to the new reference > would call either the get or set method, and would not operate on the > return value of the get. Just a note, C# does not support references to > properties, and yes, they break compatibility with variables by doing > that. How does one get a reference to a property, if a property is just a collection of methods with fancy behavior? That makes properties a first class entity, which is an entirely different bit of brain bending. (Making properties a free-form super-variable that are not bound to a class is a cool concept, but not at all what we're discussing here AFAIK.) > I imagine to get a reference to the return value of a property, you would > do something like this: > > $foo = &($bar->baz); > > > Similarly, the following does exactly what you'd expect with a normal > > class member: > > > > $foo->bar['baz']->narf = 'poink'; > > > > If $foo->bar is returned via __get(), though, then the above statement > > executes but does not actually save anything... *unless* __get() was > > defined to return by reference as above. > > Ok I think I understand what you are saying. In this case, $foo->bar is > returning an array. You then access ['baz']->narf from that array. > Arrays are always passed by reference, are they not? If so, than the > above would work fine, no? Because $foo->bar would just be returning a > reference to some array, which you then modify. Actually that's subtly wrong, which is the point I'm making. :-) If $foo->bar is a class member, then $foo->bar['baz'] dereferences from $foo to bar, does an array key lookup, finds an object, dereferences to the narf class member, and assigns "poink" to that. No new variables are ever created. If $foo->bar is accessed via __get(), then $foo->bar *returns* an array by value; the ['bar'] index of that new array is then accessed, we find an object there,that gets dereferenced to narf, and we assign 'poink' to that, in the new array. Two notes: Yes, arrays pass by value; everything passes by value in PHP unless you say otherwise with &, including objects, but objects are really handles to the actual data structure so the handle gets duplicated but still points to the same object in memory. Of course, that means in the example above the object stored at ['bar']->baz is, I think, actually a handle back to the original object inside $foo::__get() so "poink" may get set to that anyway. I'm not entirely sure. Welcome to the exciting world of PHP variable handling. My question regarding properties here would be: There are subtle and irritating differences between class members as __get() that make the latter not a true replacement for the former, especially when dealing with arrays as I've not found a way to work around those yet. What subtle and irritating differences between class members and properties would we introduce, and would they be the same subtle and irritating inconsistencies or an entirely new set of subtle and irritating inconsistencies to have to deal with? --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php