rfc:readonly_properties_v2
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:readonly_properties_v2 [2021/06/03 12:51] – nikic | rfc:readonly_properties_v2 [2021/07/01 10:16] – nikic | ||
---|---|---|---|
Line 2: | Line 2: | ||
* Date: 2021-06-02 | * Date: 2021-06-02 | ||
* Author: Nikita Popov < | * Author: Nikita Popov < | ||
- | * Status: | + | * Status: |
* Target Version: PHP 8.1 | * Target Version: PHP 8.1 | ||
* Implementation: | * Implementation: | ||
Line 76: | Line 76: | ||
<PHP> | <PHP> | ||
class Test { | class Test { | ||
- | public readonly int $prop = 0; | + | |
+ | | ||
+ | public readonly array $ary = [], | ||
+ | ) {} | ||
} | } | ||
$test = new Test; | $test = new Test; | ||
- | $test->prop += 1; | + | $test->i += 1; |
- | $test->prop++; | + | $test->i++; |
- | ++$test-> | + | ++$test-> |
- | $ref =& $test->prop; | + | $test-> |
- | $test->prop =& $ref; | + | $test-> |
- | byRef($test-> | + | $ref =& $test->i; |
+ | $test->i =& $ref; | ||
+ | byRef($test-> | ||
foreach ($test as & | foreach ($test as & | ||
</ | </ | ||
Line 154: | Line 159: | ||
==== Inheritance ==== | ==== Inheritance ==== | ||
- | It is not allowed to override a read-write | + | It is not allowed to override a read-write property with a read-only |
<PHP> | <PHP> | ||
Line 165: | Line 170: | ||
} | } | ||
</ | </ | ||
- | |||
- | However, the converse is legal: | ||
<PHP> | <PHP> | ||
Line 173: | Line 176: | ||
} | } | ||
class B extends A { | class B extends A { | ||
- | // Legal: readonly -> readwrite | + | // Illegal: readonly -> readwrite |
public int $prop; | public int $prop; | ||
} | } | ||
</ | </ | ||
+ | |||
+ | It is obvious that overriding a readwrite property with a readonly property needs to be forbidden, because that may render operations performed in the parent class invalid. However, this proposal views readonly not just as a lack of capabilities (which would be safe to increase in a child class), but as an intentional restriction. Lifting the restriction in the child class could break invariants in the parent class. As such, a readonly modifier may be neither added nor removed during inheritance. | ||
It is interesting to consider how property redeclaration interacts with the restriction that initialization can only occur in the declaring class: | It is interesting to consider how property redeclaration interacts with the restriction that initialization can only occur in the declaring class: | ||
Line 191: | Line 196: | ||
Here, initialization of '' | Here, initialization of '' | ||
- | When the same property is imported from two traits, the '' | + | When the same property is imported from two traits, the '' |
<PHP> | <PHP> | ||
Line 205: | Line 210: | ||
} | } | ||
</ | </ | ||
- | |||
- | One could argue that it should be possible to merge a readonly and a readwrite property into a readwrite property. However, other modifiers currently also require strict equality, for example it is not possible to merge a public and a protected property. If these rules should be relaxed, they should be relaxed consistently. | ||
Types on readonly properties remain invariant. One could argue that types of readonly properties could be covariant instead: | Types on readonly properties remain invariant. One could argue that types of readonly properties could be covariant instead: | ||
Line 259: | Line 262: | ||
A '' | A '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | Similarly, closure rebinding can be used to bypass the initialization scope requirement. | ||
+ | |||
+ | ==== Serialization ==== | ||
+ | |||
+ | Readonly properties have no impact on serialization. As '' | ||
+ | |||
+ | This also applies to userland serializers and hydrators. As long as the object is created using '' | ||
===== Rationale ===== | ===== Rationale ===== | ||
- | The readonly property concept introduced in this proposal provides strong immutability guarantees, which apply both inside and outside the class. Once a property has been initialized, | + | The readonly property concept introduced in this proposal provides strong immutability guarantees, which apply both inside and outside the class. Once a property has been initialized, |
+ | |||
+ | < | ||
+ | class Test { | ||
+ | public readonly string $prop; | ||
+ | |||
+ | public function method(Closure $fn) { | ||
+ | $prop = $this-> | ||
+ | $fn(); // Any code may run here. | ||
+ | $prop2 = $this-> | ||
+ | assert($prop === $prop2); // Always holds. | ||
+ | } | ||
+ | } | ||
+ | </ | ||
These guarantees are //too// strong for certain use-cases. For example, some classes may wish to have properties that are publicly readable, but can only be written from within the class. This is a much weaker guarantee, as the value of a property can change during the lifetime of an object. //Both// variants can be useful depending on the situation, and the addition of readonly properties neither precludes nor discourages the addition of asymmetric property visibility. | These guarantees are //too// strong for certain use-cases. For example, some classes may wish to have properties that are publicly readable, but can only be written from within the class. This is a much weaker guarantee, as the value of a property can change during the lifetime of an object. //Both// variants can be useful depending on the situation, and the addition of readonly properties neither precludes nor discourages the addition of asymmetric property visibility. | ||
Line 316: | Line 342: | ||
===== Vote ===== | ===== Vote ===== | ||
- | Yes/No. | + | Voting started on 2021-07-01 and closes on 2021-07-15. |
+ | |||
+ | <doodle title=" | ||
+ | | ||
+ | | ||
+ | </ | ||
rfc/readonly_properties_v2.txt · Last modified: 2021/07/20 15:37 by nikic