Hi Chad,
> Having thought a bit about this, there are a couple of initial
> problems I see, and, more importantly, I'm not convinced that the
> stated problem (encapsulation) requires the addition of a new language
> construct (i.e. a "property" as distinct from a "class member"). In
> fact, I think it is better implemented in another way (see below).
>
> First of all from a confusion point of view, PHP already has defined
> "property" in a way that opposes your RFC's definition:
> property_exists() checks for the existence of what you call a "class
> member". So, at least, it seems to me you would have to find new
> terminology if you wanted to pursue this avenue of a new construct.
>
> In my opinion, however, there should not be a new construct, and
> "property" and "class member" should remain interchangeable
> descriptions of the same class construct. I think we can do this and
> still fix the encapsulation problem.
>
> (Note: this is a long e-mail, and probably best represented in a new
> RFC. I have also written this up more completely in the form of an
> RFC, but I don't want to clutter up the wiki's RFC page unless other
> people like this idea as well, so I'll add the RFC if it looks like it
> will be useful).
>
> For example, we could do:
>
> class Time {
> protected $time;
>
> // note that $seconds, $minutes, and $hours are, in this
> // implementation, "dummies", since they will never hold
> // a value, because their "set" functions only set the $time
> // class member.
> public $seconds;
> public $minutes;
> public $hours;
>
> public function issetTime($name) isset($hours,$minutes,$seconds) {
> return isset($this->time);
> }
>
> public function unsetTime($name) unset($hours,$minutes,$seconds) {
> unset($this->time);
> }
>
> public function setTime($name, $value) set($hours,$minutes,$seconds) {
> switch($name) {
> case 'hours':
> $this->time = $value * 3600;
> break;
> case 'minutes':
> $this->time = $value * 60;
> break;
> case 'seconds':
> $this->time = $value;
> break;
> }
> $this->seconds = $seconds;
> }
>
> public function getTime($name) get($hours,$minutes,$seconds) {
> switch($name) {
> case 'hours':
> return $this->time / 3600;
> break;
> case 'minutes':
> return $this->time / 60;
> break;
> case 'seconds':
> return $this->time;
> break;
> }
> }
> }
>
> with this syntax, you could group the properties like above or, if you
> preferred, you could have a different function for each property.
>
> for read only (similar for write only), including the possibility of
> asymmetry:
>
> class Time {
> protected $time;
>
> public $seconds;
> public $minutes;
> public $hours;
>
> // ...
>
> // now Time::$hours can only be set from inside the class /
> descendents
> protected function setHours($name, $value) set($hours) {
> $this->time = $value * 3600;
> }
>
> // but Time::$hours can still be retrieved from outside the class
> public function getHours($name) get($hours) {
> return $this->time / 3600;
> }
> }
>
> for interfaces:
>
> interface TimeClass {
> public function setHours($name, $value) set($hours);
> }
>
> This has a number of benefits:
>
> 1. This "acts like PHP", and also brings along features "out of the box"
> (a) The new syntax mimics the form of the syntax of closures ($x =
> function() use($a, $b) { // ... };), so it is somewhat familiar.
> (b) The arguments of the isset, unset, getters and setters is
> analogous to that in the __get and __set methods, so userland
> implementation will be familiar.
> (c) The getters and setters are still regular class methods, so they
> can be called as methods as usual (subject to visibility, of course)
> (d) Adds "shades" to the read-only and write-only concepts via
> visibility modifiers!
> (e) Isset / unset make sense now! E.g. that when unsetting $hours, we
> actually want to unset the time in general. In fact, this is
> preferred, because in the examples we've been looking at, the "magic"
> is in "grouping" the three class members (seconds, minutes, hours),
> and this implementation of isset and unset allow you to do just that
> grouping, without having to write 3 isset and 3 unset functions, as
> you would have to in the property definition.
> (f) This allows for much more compact class definitions, as you don't
> have to define getHours(), getMinutes(), getSeconds() individually if
> you don't want to (although it allows you the flexibility to do that
> if it's what you want).
> (g) Inheritance works out of the box.
> (h) Final keyword works out of the box.
> (i) Documentation works out of the box (just do it as you do it now,
> on the class members and the methods).
> (j) Interfaces work.
> (k) In the example above, the class could go ahead and set the
> Time::$time class member directly without incurring the overhead of
> the getter / setter functions!
>
> 2. Fixes the stated problems
> (a) Adds the syntactic sugar to complex getting and setting.
> (b) Gives read-only / write-only
> (c) Fixes the ambiguity of __get and __set in terms of what class
> members are defined.
>
> -----------
Interesting, however I don't see anything tangible in your proposal that
would give any benefit over just using regular methods. Besides, I think
your proposal would serve a very different purpose than my property
proposal.
> On another note, given our current parser, as I understand it,
> defining the new keywords of "get" and "set" will not be possible
> because of a BC break - for people using get and set as the names of
> classes, methods, or functions. This means that for both your RFC and
> for my suggestion, a new keyword will have to be found, unless this is
> put in a new major version and people are comfortable with it. I also
> think __get, __set are out because they are in use as the magic
> methods...any suggestions?
Interesting. So you are saying that once a word is a keyword in PHP, it
cannot be used as a name, anywhere? So for example, you are saying I
cannot create a variable called $function? If that is the case, that is
extremely odd. I would expect that get/set could be keywords when used in
the right location (inside a property definition, but outside of the
property body), but anywhere else they should be able to be used as a
regular name... Is there some way that could be possible?
- Dennis
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php