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

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

Reply via email to