rfc:propertygetsetsyntax-as-implemented:change-requests

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:propertygetsetsyntax-as-implemented:change-requests [2012/10/26 10:50] – Updated to move read-only keyword removal to consensus, other minor changes. cpriestrfc:propertygetsetsyntax-as-implemented:change-requests [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 6: Line 6:
  
 ==== Syntax Change ==== ==== Syntax Change ====
-Change syntax to use public set($value) {}, public get(), etc. Along with that means no “magic” $value in the setter+<del>[[https://github.com/cpriest/php-src/issues/6|https://github.com/cpriest/php-src/issues/6]]</del> 
 + 
 +Allow syntax to use parenthesized syntax as well so that both a [TypeHint] and $value may be specified. 
 <code php> <code php>
 class TimePeriod { class TimePeriod {
Line 19: Line 22:
 } }
 </code> </code>
 +
 +The abbreviated syntax is also allowed as per 1.1 RFC.
  
 ==== read-only / write-only keywords ==== ==== read-only / write-only keywords ====
 +<del>[[https://github.com/cpriest/php-src/issues/7|https://github.com/cpriest/php-src/issues/7]]</del>
 +
 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: 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:
  
Line 37: Line 44:
  
 ==== Automatically Implemented Accessors ==== ==== Automatically Implemented Accessors ====
 +[[https://github.com/cpriest/php-src/issues/5|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. 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.
  
Line 67: Line 76:
 </code> </code>
  
-=== Potential Issues === +==== Shadowing ==== 
-  Decreased performance due to accessor check against any property access, could possibly be next to no impact depending on implementation (property structure with pointer to accessor structure). +[[https://github.com/cpriest/php-src/issues/11|https://github.com/cpriest/php-src/issues/11]]
- +
  
-===== Being Debated =====+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.
  
-==== Shadowing ==== +<code php> 
-v1.1 has properties shadow accessors, the suggestion is that this be inverted.+class TimePeriod { 
 +    private $Seconds;
  
-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().+    public $Seconds { 
 +        get() { return $this->Seconds; /* Accesses the private $Seconds directly */ } 
 +        set($x{ $this->Seconds = $x; /* Accesses the private $Seconds directly */ } 
 +    } 
 +}
  
-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.  +$o = new TimePeriod(); 
 +$o->Seconds = 45;  /* Calls set accessor */ 
 +echo $o->Seconds;  /* Calls get accessor */ 
 +</code>
  
-v1.2 proposal seems to make the most sense however it would incur a slight (possibly *very* slight) performance penalty.+==== isset / unset / attempted writes when no setter / attempted reads when no getter ==== 
 +[[https://github.com/cpriest/php-src/issues/12|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.
 +
 +<code php>
 +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 */
 +</code>
 +
 +==== Extra shorthand declaration ====
 +
 +Not much further support and good arguments against it, dropped.
 +
 +==== Interfaces ====
 +[[https://github.com/cpriest/php-src/issues/13|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.
 +<code php>
 +interface i {
 +    public $Seconds { get; }
 +}
 +
 +class TimePeriod implements i {
 +
 +    /* Satisfies interface implementation requirements of interface i */
 +    public $Seconds;
 +}
 +
 +</code>
 +
 +===== Being Debated =====
  
 ==== internal accessor method visibility / callability ==== ==== internal accessor method visibility / callability ====
Line 104: Line 160:
  
 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)//. 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)//.
- 
-==== isset / unset / attempted writes when no setter / attempted reads when no getter ==== 
-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): 
-  - If all cases can be tested for during compilation, prefer compile failures. 
-  - Let the compilation occur and at runtime when a disallowed action is attempted, emit a warning and move on. 
-  - As is currently, either at compilation or at runtime we issue a fatal error and stop execution (probably least preferable if at runtime) 
- 
-==== Interfaces ==== 
-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. 
- 
-=== Arguments For === 
-  - From the outside observer of an interface, a class which defines a property has satisfied the requirement, because an interface only defines what must be allowed, not what cannot be done. 
- 
-=== Arguments Against === 
-  - Additional overhead on interface checking, would only be allowed for a non-asymmetrical accessor 
-  - Would give userland developers the ability to write poor code as properties are non-observable (object would not know its property was changed) 
- 
-==== Extra shorthand declaration ==== 
-Allow extra short declaration of an accessor: 
-<code php> 
-class TimePeriod { 
-    public DateTime $date; 
-} 
- 
-/* Would be equivalent to this */ 
- 
-class TimePeriod { 
-    public $date { 
-        get() { return $this->date; } 
-        set(DateTime $value) { $this->date = $value;} 
-    } 
-} 
-</code> 
  
 ===== Issues ===== ===== Issues =====
Line 151: Line 172:
 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. 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.
 ===== TODO ===== ===== TODO =====
-  - Exceptions thrown from an accessor reveal underlying implementation details +  - <del>Exceptions thrown from an accessor reveal underlying implementation details</del> [[https://github.com/cpriest/php-src/issues/14|github#14]] 
-  - get_class_methods() - hide accessors or re-write to call into Reflection* code? +  - <del>get_class_methods() - hide accessors or re-write to call into Reflection* code?</del> [[https://github.com/cpriest/php-src/issues/15|github#15]] 
-  - Check debug_backtrace() output as well +  - <del>Check debug_backtrace() output as well</del> [[https://github.com/cpriest/php-src/issues/16|github#16]] 
-  - Add notes to RFC on shadowing behavior of properties and acessors +  - <del>Add notes to RFC on shadowing behavior of properties and acessors [[https://github.com/cpriest/php-src/issues/17|github#17]]</del> 
-  - Fix automatically implemented isset to use !== rather than != (Thanks Stas!) +  - <del>Fix automatically implemented isset to use !== rather than != (Thanks Stas!)</del> 
-  - Check that the following should work and write tests for them: +  - <del>Check that the following should work and write tests for them:</del> [[https://github.com/cpriest/php-src/issues/18|github#18]] 
-    - $foo->bar[] = 1 +    - <del>$foo->bar[] = 1</del> 
-    - $foo->bar[123] = 4 +    - <del>$foo->bar[123] = 4</del> 
-    - $foobar = &$foo->bar +    - <del>$foobar = &$foo->bar</del> 
-    - $foo->bar->baz = $x with $bar being object or empty or non-object value (proper error and no leaks -- Stas) +    - <del>$foo->bar->baz = $x with $bar being object or empty or non-object value (proper error and no leaks -- Stas)</del> 
-    - $foo->bar{$x} = "foo" (string offsets), also checks that non-string vars work fine +    - <del>$foo->bar{$x} = "foo" (string offsets), also checks that non-string vars work fine</del> 
-    - $foo->bar = &bar->baz, etc. with modifying both sides and checking everything works (including modifying via accessors -- Stas) +    - <del>$foo->bar = &bar->baz, etc. with modifying both sides and checking everything works (including modifying via accessors -- Stas)</del> 
-  - Expand on the "Error Messaging" with examples of what has been translated.+  - <del>Expand on the "Error Messaging" with examples of what has been translated. [[https://github.com/cpriest/php-src/issues/17|github#17]]</del> 
 +  - <del>Move all accessor tests into Zend/tests/accessors</del>
  
 ===== Previously Debated ===== ===== Previously Debated =====
Line 213: Line 235:
 } }
 </code> </code>
 +
 +==== 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.
 +
 +==== isset / unset / attempted writes when no setter / attempted reads when no getter ====
 +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):
 +  - If all cases can be tested for during compilation, prefer compile failures.
 +  - Let the compilation occur and at runtime when a disallowed action is attempted, emit a warning and move on.
 +  - As is currently, either at compilation or at runtime we issue a fatal error and stop execution (probably least preferable if at runtime)
 +
 +==== Extra shorthand declaration ====
 +Allow extra short declaration of an accessor:
 +<code php>
 +class TimePeriod {
 +    public DateTime $date;
 +}
 +
 +/* Would be equivalent to this */
 +
 +class TimePeriod {
 +    public $date {
 +        get() { return $this->date; }
 +        set(DateTime $value) { $this->date = $value;}
 +    }
 +}
 +</code>
 +
 +==== Interfaces ====
 +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.
 +
 +=== Arguments For ===
 +  - From the outside observer of an interface, a class which defines a property has satisfied the requirement, because an interface only defines what must be allowed, not what cannot be done.
 +
 +=== Arguments Against ===
 +  - Additional overhead on interface checking, would only be allowed for a non-asymmetrical accessor
 +  - Would give userland developers the ability to write poor code as properties are non-observable (object would not know its property was changed)
 +
rfc/propertygetsetsyntax-as-implemented/change-requests.1351248644.txt.gz · Last modified: 2017/09/22 13:28 (external edit)