[RFC] Property Accessors 1.2 : Shadowing

php.internals

Clint M Priest

13 years ago
I'm opening up several new threads to get discussion going on the remaining "being debated" categories referenced in this 1.1 -> 1.2 change spec: https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests Shadowing 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. Thoughts?
-- -Clint

Stas Malyshev

13 years ago
Hi!
> 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.
One of the deficiencies frequently mentioned for __get was "what if I want to override access for existing variable?" Given that, I think accessor priority is a good thing. Now, with direct access from within the accessor it may get a bit tricky, especially considering loops, etc. What would happen in the scenario of __getHours calling foo() which does "return $this->Hours"? Is __getHours called again? Is it a fatal error? Does it return "undefined" like __get does?
> v1.2 proposal seems to make the most sense however it would incur a > slight (possibly *very* slight) performance penalty.
It may be an extra hash lookup, but if we could probably add the existence of accessor (or maybe even pointer) into zend_property_info then we wouldn't need the second hash lookup probably.
-- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/ (408)454-6900 ext. 227

Clint M Priest

13 years ago
Recursion is guarded by the same mechanism __get uses to avoid recursion. On 10/26/2012 9:33 AM, Stas Malyshev wrote:
> Hi! > >> 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. > One of the deficiencies frequently mentioned for __get was "what if I > want to override access for existing variable?" Given that, I think > accessor priority is a good thing. > Now, with direct access from within the accessor it may get a bit > tricky, especially considering loops, etc. What would happen in the > scenario of __getHours calling foo() which does "return $this->Hours"? > Is __getHours called again? Is it a fatal error? Does it return > "undefined" like __get does? > >> v1.2 proposal seems to make the most sense however it would incur a >> slight (possibly *very* slight) performance penalty. > It may be an extra hash lookup, but if we could probably add the > existence of accessor (or maybe even pointer) into zend_property_info > then we wouldn't need the second hash lookup probably.
-- -Clint

Stas Malyshev

13 years ago
Hi!
> Recursion is guarded by the same mechanism __get uses to avoid recursion.
__get on recursion returns undefined, __set on recursion does nothing. However you're saying "No direct access to the property would be allowed except from within the accessor" - but what this not allowing means? Just returning undefined if __getHours was previously called?
-- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/ (408)454-6900 ext. 227

Clint M Priest

13 years ago
Sorry I guess I should have been more clear. The recursion would prevent the accessor from being called which would allow the ordinary property code to execute, thus accessing the property directly. I suppose if it were in a setter and the property were not defined by the accessor then it would automagically create a public property, not that it would matter if accessors always shadowed properties because the access control of the accessor would still prevail. But it could be written such that an accessor would define a private property upon set from within the setter. Recursion guarding in this case simply means that the get/set is guarded from being called more than once. It's the same mechanism that __get and __set use. On Saturday, October 27, 2012 3:20:38 PM, Stas Malyshev wrote:
> Hi! > >> Recursion is guarded by the same mechanism __get uses to avoid recursion. > > __get on recursion returns undefined, __set on recursion does nothing. > However you're saying "No direct access to the property would be allowed > except from within the accessor" - but what this not allowing means? > Just returning undefined if __getHours was previously called? >
-- -Clint

Stas Malyshev

13 years ago
Hi!
> Sorry I guess I should have been more clear. The recursion would > prevent the accessor from being called which would allow the ordinary > property code to execute, thus accessing the property directly. I
This could lead to weird scenarios where the same $foo->bar in random function could call or not call an accessor depending on the stack trace (provided that accessors call out to other functions - which is not frequent but can definitely happen). In case of __get it's harmless since we know $foo->bar doesn't exist anyway, but if we do allow $bar to exist in $foo it might get weird. I'd certainly appreciate some notice/E_STRICT if this happens. Maybe I'd go even as far as issuing E_STRICT on having both $bar and any of the accessors for $bar in the same class - but this of course would scream on the scenario of augmenting existing $bar with accessors - which is legit, unless it gets weird as described above.
-- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/ (408)454-6900 ext. 227

Clint M Priest

13 years ago
Well I guess this and many of the other issues from other threads are the reasons I had it written the way that it is currently (basically an extension of __get()) but numerous other proposals have muddied the situation. On Sunday, October 28, 2012 2:17:47 AM, Stas Malyshev wrote:
> Hi! > >> Sorry I guess I should have been more clear. The recursion would >> prevent the accessor from being called which would allow the ordinary >> property code to execute, thus accessing the property directly. I > > This could lead to weird scenarios where the same $foo->bar in random > function could call or not call an accessor depending on the stack trace > (provided that accessors call out to other functions - which is not > frequent but can definitely happen). In case of __get it's harmless > since we know $foo->bar doesn't exist anyway, but if we do allow $bar to > exist in $foo it might get weird. I'd certainly appreciate some > notice/E_STRICT if this happens. > Maybe I'd go even as far as issuing E_STRICT on having both $bar and any > of the accessors for $bar in the same class - but this of course would > scream on the scenario of augmenting existing $bar with accessors - > which is legit, unless it gets weird as described above.
-- -Clint