https://github.com/cpriest/php-src/issues/6
Allow syntax to use parenthesized syntax as well so that both a [TypeHint] and $value may be specified.
class TimePeriod { private $Seconds; public $Hours { get() { return $this->Seconds / 3600; } set([TypeHint] $value) { $this->Seconds = $value * 3600; } isset() { return isset($this->Seconds); } unset() { unset($this->Seconds); } } }
The abbreviated syntax is also allowed as per 1.1 RFC.
https://github.com/cpriest/php-src/issues/7
read-only / write-only keywords will be eliminated, the issue will be pushed to userland developers who can enforce the same by coding something like this:
class TimePeriod { private $Seconds; public $Hours { get() { return $this->Hours; } private final set($value) { throw new Exception("Setting of TimePeriod::$Hours is not allowed."); } } }
This was previously being debated, the full details of this are in the last section under “Previously Debated”
https://github.com/cpriest/php-src/issues/5
v1.1 properties shadow (or over-ride) accessors, so if an accessor exists and a property is defined (only possible from within the accessors setter), then the property would shadow the accessor. This was done to keep it consistent with what __get() does and also to support lazy loading.
Nikita suggested that this should be inverted, that accessors shadow properties. With that comes the advantage that automatically implemented get/set could use the same property name as the accessor (no more magic $__Hours property):
class TimePeriod { private $Seconds; public $Hours { get(); set([TypeHint] $value); isset(); unset(); } } /* Would automatically be implemented as */ class TimePeriod { private $Seconds; public $Hours { get() { return $this->Hours; } set([TypeHint] $value) { $this->Hours = $value; } isset() { return $this->Hours !== NULL; } unset() { $this->Hours = NULL; } } }
https://github.com/cpriest/php-src/issues/11
Accessors will shadow properties such that if a property named $foo is declared and an accessor for $foo is declared, the accessor will be used instead, only the accessor will have direct access to the underlying property.
class TimePeriod { private $Seconds; public $Seconds { get() { return $this->Seconds; /* Accesses the private $Seconds directly */ } set($x) { $this->Seconds = $x; /* Accesses the private $Seconds directly */ } } } $o = new TimePeriod(); $o->Seconds = 45; /* Calls set accessor */ echo $o->Seconds; /* Calls get accessor */
https://github.com/cpriest/php-src/issues/12
Invalid calls to isset/unset will fail silently and return false in the case of isset(), no warning/notice should be thrown.
class TimePeriod { private $Seconds; protected $Seconds { get() { return $this->Seconds; /* Accesses the private $Seconds directly */ } set($x) { $this->Seconds = $x; /* Accesses the private $Seconds directly */ } } } $o = new TimePeriod(); isset($o->Seconds); /* Returns false, no error thrown */ unset($o->Seconds); /* Does nothing, no error thrown */
Not much further support and good arguments against it, dropped.
https://github.com/cpriest/php-src/issues/13
An implementing class may specify a property with an appropriate access level to satisfy an accessor declaration requirement of an interface.
interface i { public $Seconds { get; } } class TimePeriod implements i { /* Satisfies interface implementation requirements of interface i */ public $Seconds; }
Some people are in favor of the internal functions being generated by an accessor declaration should be invisible and non-callable directly. Others are in favor of leaving them visible and callable.
As a userland programmer, someone who cares nothing for “how” php works, only how their own code works. If they define an accessor they expect to see an accessor, reflection should reflect that there are accessors and no other “methods” they did not explicitly define. If they were to reflect on all of the methods of their class and see a number of __getHours() they may be confused as to why or where this function came from. From their perspective, they have defined an accessor and “how” that accessor works on the inside is of no importance to them and only seeks to complicate or confuse matters when they are exposed to these “implementation details” of the php language its-self. If you tried to set a value such as $obj->abc = 1 through an accessor which could not be set, you would probably want to see an error like: Warning, cannot set Class->abc, no setter defined.
As an internals programmer, you want nothing hidden from you. If an accessor implements special __getHours() methods to work its magic, then you want to see them, you want to call them directly if you so choose. In effect you want nothing hidden from you. In this case you probably don't even want Reflection to reflect accessors as anything different than specially formatted and called methods on the class. This can be understandable because you want all information available to you. You would probably not be confused if you wrote $obj->abc = 1 and got back an error like “Fatal Error: Class->__setAbc() function does not exist.
Unfortunately 80 to 95% of all people who use PHP are of the first type.
Revealing these internal matters to them would only leave them confused, possibly frustrated and likely asking about it to the internals mailing list to answer (repeatedly).
Stas pointed out a number of critical mistakes with the current implementation of static accessors. They would not currently work under these circumstances:
The current implementation “back-patches” the op_array at the time of a static variable declaration by patching the op array into a method call. zend_do_assign() further detects these calls to ex: __getStaticHours() into __setStaticHours(), and a change to pass_two() detects invalid static accessor gets (those which were not properly backpatched with zend_do_assign())
Stas suggested that he could either help me to implement this more appropriately (such as changing the engine to make calls into zend_object_handler.c) so that these calls can be resolved dynamically, or that static accessors be shelved for a future version of accessors.
Update 12/30/2012: Too much engine work is necessary to implement static accessors, this is being pushed to a future RFC change.
read-only / write-only keywords replacement. Just about everyone is against these two new keywords, no equivalent replacement has been suggested (see below).
For Clarity: read-only enforces upon the defining class and all sub-classes that no setter may be defined, a type of final that restricts the defining of a setter. The inverse is true for write-only.
Possible alternatives:
This would prevent sub-classes from changing the setter, however this would produce an automatically implemented setter which would be callable from within the defining class. It's close, but not identical.
class TimePeriod { private $Seconds; public $Hours { get() { return $this->Hours; } private final set([TypeHint] $value); } }
This could be an alternative that could be implemented internally exactly the same as a read-only or write-only:
class TimePeriod { private $Seconds; public $Hours { get() { return $this->Hours; } final set NULL; } }
I have also suggested that perhaps the read-only and write-only functionality (type of final) is not even needed or desired.
Possible Consensus: Eliminate read-only/write-only keywords and let userland programmers enforce it with something like:
class TimePeriod { private $Seconds; public $Hours { get() { return $this->Hours; } private final set($value) { throw new Exception("Setting of TimePeriod::$Hours is not allowed."); } } }
v1.1 has properties shadow accessors, the suggestion is that this be inverted.
Specifically this means that in v1.1, if an accessor is defined and no property is defined, then the accessor will be used. But when a property is assigned/declared then the property will “shadow” the accessor and the accessor will no longer be used until the property is unset().
v1.2 Proposes that this be inverted such that if there is an accessor defined for a given property name, the accessor will always be used. The accessor would be able to get/set/isset/unset the property with the same name as the accessor. No direct access to the property would be allowed except from within the accessor.
v1.2 proposal seems to make the most sense however it would incur a slight (possibly *very* slight) performance penalty.
Stas suggested that since there is presently no cases where these can fail that with accessors these should never “fail.”
Three possible ways to go (maybe others):
Allow extra short declaration of an accessor:
class TimePeriod { public DateTime $date; } /* Would be equivalent to this */ class TimePeriod { public $date { get() { return $this->date; } set(DateTime $value) { $this->date = $value;} } }
v1.1 fully allows accessors to be defined in interfaces and requires that those accessors be defined in implementing classes. Some people have suggested that a property defined by the class should also satisfy the requirement.