rfc:property_accessors

Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
rfc:property_accessors [2021/05/04 08:42]
nikic
rfc:property_accessors [2022/04/28 09:30] (current)
ilutov Fix typos
Line 3: Line 3:
   * Author: Nikita Popov <nikic@php.net>   * Author: Nikita Popov <nikic@php.net>
   * Proposed Version: PHP 8.1   * Proposed Version: PHP 8.1
-  * Implementation: https://github.com/php/php-src/pull/6873 (WIP) +  * Implementation: https://github.com/php/php-src/pull/6873 
-  * Status: Draft+  * Status: Under Discussion
  
 ===== Introduction ===== ===== Introduction =====
Line 363: Line 363:
 </PHP> </PHP>
  
-Specifying the same accessor multiple types is also illegal.+Specifying the same accessor multiple times is also illegal.
  
 === By-reference getter === === By-reference getter ===
Line 387: Line 387:
 </PHP> </PHP>
  
-These indirect modification perform a call to the getter, followed by a call to the setter.+These indirect modifications perform a call to the getter, followed by a call to the setter.
  
 However, indirect array modification, as well as acquiring a reference are only supported by by-reference getters. In this case, the setter will not be invoked: However, indirect array modification, as well as acquiring a reference are only supported by by-reference getters. In this case, the setter will not be invoked:
Line 420: Line 420:
  
 While nominally well-defined, such an accessor would not have particularly useful semantics: It would be possible to change the property value arbitrarily, but only by writing ''$ref =& $test->prop; $ref = $value'' rather than ''$test->prop = $value''. While nominally well-defined, such an accessor would not have particularly useful semantics: It would be possible to change the property value arbitrarily, but only by writing ''$ref =& $test->prop; $ref = $value'' rather than ''$test->prop = $value''.
 +
 +TODO: An open problem is how implicit by-value ''get'' interacts with by-reference foreach. Currently, it's still possible to acquire a reference using this pathway:
 +
 +<PHP>
 +class Test {
 +    public $prop = null { get; private set; }
 +}
 +
 +$test = new Test;
 +foreach ($test as &$prop) {
 +    $prop = 1;
 +}
 +</PHP>
 +
 +This needs to be prevented in some way. This could either error, or it could silently return a value for properties for which no reference can be acquired. Otherwise it would no longer be possible to iterate arbitrary objects by-reference.
  
 === Isset and unset === === Isset and unset ===
Line 499: Line 514:
 === Interaction with by-reference getter === === Interaction with by-reference getter ===
  
-It is worth pointing out that the combination of ''&get'' with ''private set'' leaves a loophole that allows you do bypass the private setter and perform arbitrary modifications:+It is worth pointing out that the combination of ''&get'' with ''private set'' leaves a loophole that allows you to bypass the private setter and perform arbitrary modifications:
  
 <PHP> <PHP>
Line 524: Line 539:
 class A { class A {
     public $prop {     public $prop {
-        get { echo __METHOD, "\n";+        get { echo __METHOD__, "\n";
-        set { echo __METHOD, "\n"; }+        set { echo __METHOD__, "\n"; }
     }     }
 } }
 class B extends A { class B extends A {
     public $prop {     public $prop {
-        set { echo __METHOD, "\n"; }+        set { echo __METHOD__, "\n"; }
     }     }
 } }
Line 550: Line 565:
     public int|string $covariant { get; }     public int|string $covariant { get; }
     // This property is useless, but will serve for the sake of illustration.     // This property is useless, but will serve for the sake of illustration.
-    public int|string $contravariant { set {} }+    public int|string $contravariant { set { /* ... */ } }
 } }
  
Line 905: Line 920:
 class Test { class Test {
     // Illegal: Implicit get, explicit set.     // Illegal: Implicit get, explicit set.
-    public string $prop { get; set {} }+    public string $prop { 
 +        get; 
 +        set { /* ... */ } 
 +    }
     // Illegal: Implicit set, explicit get.     // Illegal: Implicit set, explicit get.
-    public string $prop { get {} set; }+    public string $prop { 
 +        get { /* ... */ } 
 +        set; 
 +    }
 } }
 </PHP> </PHP>
Line 930: Line 951:
     // Illegal: Default value on property with explicit accessors.     // Illegal: Default value on property with explicit accessors.
     public $prop = "" {     public $prop = "" {
-        get {}+        get { /* ... */ }
     }     }
 } }
Line 963: Line 984:
 This limitation exists to prevent embedding of very large property declarations in the constructor signature. This limitation exists to prevent embedding of very large property declarations in the constructor signature.
  
-=== var_dump, get_object_vars() etc ===+=== var_dump(), array cast, foreach etc ===
  
-''var_dump()'', and other functions or language features inspecting object properties will only return properties that have a backing property, i.e. those using implicit accessors. Explicit accessor properties are omitted, and accessors will never be evaluated as part of a ''var_dump()'', ''(array)'' casts, or similar.+''var_dump()'', ''(array)'' casts, foreach and other functions/features inspecting object properties will only return properties that have a backing property, i.e. those using implicit accessors. Explicit accessor properties are omitted, and accessors will never be evaluated as part of a ''var_dump()'', ''(array)'' cast, foreach, or similar.
  
 <PHP> <PHP>
Line 979: Line 1000:
 //   int(42) //   int(42)
 // } // }
 +
 +var_dump((array) $test);
 +// array(1) {
 +//   ["prop1"]=>
 +//   int(42)
 +// }
 +
 +foreach ($test as $name => $value) {
 +    echo "$name: $value\n";
 +}
 +// prop1: 42
 </PHP> </PHP>
  
Line 1059: Line 1091:
 No backwards-incompatible changes are known. Due to the existence of magic get/set the introduction of accessors also shouldn't break existing assumptions much. One potential assumption break is that accessor properties cannot be unset. No backwards-incompatible changes are known. Due to the existence of magic get/set the introduction of accessors also shouldn't break existing assumptions much. One potential assumption break is that accessor properties cannot be unset.
  
-==== Reserved Keywords ====+==== Reserved keywords ====
  
 The accessor names ''get'' and ''set'' are **not** added as reserved keywords, and are contextually disambiguated instead. The accessor names ''get'' and ''set'' are **not** added as reserved keywords, and are contextually disambiguated instead.
Line 1075: Line 1107:
  
 This is not a backwards-compatibility break, but mentioned for completeness. This is not a backwards-compatibility break, but mentioned for completeness.
 +
 +===== Discussion =====
 +
 +This is a fairly complex proposal, and is likely to grow more complex as remaining details are ironed out. I have some doubts that the complexity is truly justified.
 +
 +I think there are really two parts to this proposal, even if they are tightly related in the form presented here:
 +
 +  - Implicit accessors, which allow finely controlling property access. They support both read-only and private-write properties.
 +  - Explicit accessors, which allow implementing arbitrary behavior.
 +
 +My expectation is that implicit accessors will see heavy use, as read-only properties are a very common requirement. Explicit accessors on the other hand should be used rarely, and primarily as a means to maintain backwards-compatibility with an existing API. If it is known in advance that a property needs to be associated with non-trivial behavior, then it is preferable to implement it using methods in the first place.
 +
 +We could likely get 80% of the value of accessors by supporting read-only properties and 90% by also supporting private-write properties. A previous proposal for read-only properties was the [[rfc:write_once_properties|write-once properties RFC]]. While this particular proposal has been declined, I do think that the general approach was sound, and could be accepted.
  
 ===== Vote ===== ===== Vote =====
  
 +TBD.
rfc/property_accessors.1620117754.txt.gz · Last modified: 2021/05/04 08:42 by nikic