Hi Larry,

>> Its not a matter of consistency - Properties, as a cross-language
>> concept
>> are not meant to work that way.  You need to think of a property as a
>> set
>> of two methods that just have a pretty syntax.  Methods cannot be unset,
>> and nor should properties be allowed to.  isset() should simply tell us
>> whether a property with the specified name is part of the class or not.
>>
>> isset() in the way you suggest would just be confusing.  It would allow
>> is
>> to say that a property does not exist, when in fact it does exist.  This
>> is not logical.
>
> Consistency with other languages must also be balanced against
> consistency within PHP.  Both are important.
>
> Class members and both existing class-member-ish mechanisms (__magic and
> ArrayAccess) have the concept of isset/unset.  A third class-member-ish
> (syntactically speaking) mechanism will be expected to have the same set
> of primitives.  To not have them will be a major language WTF, because
> to a normal user of an object they *look* like class members, not
> methods, they *taste* like class members, not methods, so they should
> *act* like class members, not methods.
>
> Basically, properties can only be considered a drop-in replacement for
> class members (as you've stated, correctly, is one of the potential big
> wins for them) if they fully emulate their behavior.  If they do not,
> then it is incorrect to say that they can be swapped in for a class
> member without changing an API.

Yes, you are correct, if they are to be a full drop-in replacement, they
must handle isset/unset as expected.  This is something I had not thought
of earlier.


>> __isset() is a whole different matter, without it we would have to
>> assume
>> that every possible member name either exists or does not exist.  This
>> is
>> because __isset can handle ANY member name.
>>
>> Properties are bound to a single member name, therefore, they always
>> exist, unless you were to physically remove that property from the
>> class,
>> which, like methods, that is not possible.
>
> No, but it can be easily emulated.
>
> 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!)


> 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.

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.

This is how it works in C#.  Note, however, if you do the same thing with
a "value" type instead of a "reference" type in C#, it will not work as
you described above, because you would be modifying a value, not a
reference.

- Dennis


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to