From 16f66c05a4060a7d673ae1c70b656d65009407b0 Mon Sep 17 00:00:00 2001 From: Larry Garfield Date: Tue, 15 Oct 2024 18:49:15 +0000 Subject: [PATCH] Asymmetric Visibility and Final properties (#3828) * Document asymmetric property visibility. * Document the change in implicit visibility for readonly. * Document final properties. * Note that isPublic/Protected/Private is only in reference to the main visibility. * Use more note tags. * Remove unnecessary para tags. Co-authored-by: Christoph M. Becker --- language/oop5/final.xml | 37 +++-- language/oop5/properties.xml | 8 +- language/oop5/visibility.xml | 152 +++++++++++++++--- .../reflectionproperty/isprivate.xml | 5 + .../reflectionproperty/isprotected.xml | 5 + .../reflectionproperty/ispublic.xml | 7 +- 6 files changed, 183 insertions(+), 31 deletions(-) diff --git a/language/oop5/final.xml b/language/oop5/final.xml index e2f28aef7d74..3c27186b2a6b 100644 --- a/language/oop5/final.xml +++ b/language/oop5/final.xml @@ -3,7 +3,7 @@ Final Keyword - The final keyword prevents child classes from overriding a method or constant by + The final keyword prevents child classes from overriding a method, property, or constant by prefixing the definition with final. If the class itself is being defined final then it cannot be extended. @@ -59,10 +59,26 @@ class ChildClass extends BaseClass { - - - Final constants example as of PHP 8.1.0 - + + Final property example as of PHP 8.4.0 + + +]]> + + + + Final constants example as of PHP 8.1.0 + ]]> - - - + + - Properties cannot be declared final: only classes, methods, and constants (as of PHP 8.1.0) may be declared as final. + As of PHP 8.0.0, private methods may not be declared final except for the constructor. + + - As of PHP 8.0.0, private methods may not be declared final except for the constructor. + A property that is declared private(set) is implicitly final. diff --git a/language/oop5/properties.xml b/language/oop5/properties.xml index 40ce1ea63d8d..106df043e945 100644 --- a/language/oop5/properties.xml +++ b/language/oop5/properties.xml @@ -192,7 +192,13 @@ Fatal error: Uncaught Error: Typed property Shape::$numberOfSides must not be ac Readonly properties - As of PHP 8.1.0, a property can be declared with the readonly modifier, which prevents modification of the property after initialization. + As of PHP 8.1.0, a property can be declared with the readonly modifier, + which prevents modification of the property after initialization. Prior to PHP 8.4.0 + a readonly property is implicitly private-set, and may only be written to + from the same class. As of PHP 8.4.0, readonly properties are implicitly + protected(set), + so may be set from child classes. That may be overridden + explicitly if desired. Example of readonly properties diff --git a/language/oop5/visibility.xml b/language/oop5/visibility.xml index 7307b7af3694..8d5c568d5af7 100644 --- a/language/oop5/visibility.xml +++ b/language/oop5/visibility.xml @@ -20,10 +20,9 @@ protected. Properties declared without any explicit visibility keyword are defined as public. - - - Property declaration - + + Property declaration + private; // Undefined $obj2->printHello(); // Shows Public2, Protected2, Undefined ?> +]]> + + + + Asymmetric Property Visibility + + As of PHP 8.4, properties may also have their + visibility set asymmetrically, with a different scope for + reading (get) and writing (set). + Specifically, the set visibility may be + specified separately, provided it is not more permissive than the + default visibility. + + + Asymmetric Property visibility + +author = $author; // OK + $this->pubYear = $year; // Fatal Error + } +} + +$b = new Book('How to PHP', 'Peter H. Peterson', 2024); + +echo $b->title; // Works +echo $b->author; // Works +echo $b->pubYear; // Fatal Error + +$b->title = 'How not to PHP'; // Fatal Error +$b->author = 'Pedro H. Peterson'; // Fatal Error +$b->pubYear = 2023; // Fatal Error +?> ]]> - + There are a few caveats regarding asymmetric visibility: + + + + Only typed properties may have a separate set visibility. + + + + + The set visibility must be the same + as get or more restrictive. That is, + public protected(set) and protected protected(set) + are allowed, but protected public(set) will cause a syntax error. + + + + + If a property is public, then the main visibility may be + omitted. That is, public private(set) and private(set) + will have the same result. + + + + + A property with private(set) visibility + is automatically final, and may not be redeclared in a child class. + + + + + Obtaining a reference to a property follows set visibility, not get. + That is because a reference may be used to modify the property value. + + + + + Similarly, trying to write to an array property involves both a get and + set operation internally, and therefore will follow the set + visibility, as that is always the more restrictive. + + + + + When a class extends another, the child class may redefine + any property that is not final. When doing so, + it may widen either the main visibility or the set + visibility, provided that the new visibility is the same or wider + than the parent class. However, be aware that if a private + property is overridden, it does not actually change the parent's property + but creates a new property with a different internal name. + + + Asymmetric Property inheritance + + +]]> + + + @@ -87,10 +205,9 @@ $obj2->printHello(); // Shows Public2, Protected2, Undefined protected. Methods declared without any explicit visibility keyword are defined as public. - - - Method Declaration - + + Method Declaration + test(); // Bar::testPrivate // Foo::testPublic ?> ]]> - - - + + @@ -188,10 +304,9 @@ $myFoo->test(); // Bar::testPrivate protected. Constants declared without any explicit visibility keyword are defined as public. - - - Constant Declaration as of PHP 7.1.0 - + + Constant Declaration as of PHP 7.1.0 + foo2(); // Public and Protected work, not Private ?> ]]> - - - + + diff --git a/reference/reflection/reflectionproperty/isprivate.xml b/reference/reflection/reflectionproperty/isprivate.xml index 1561f26ad66b..f572012bad2d 100644 --- a/reference/reflection/reflectionproperty/isprivate.xml +++ b/reference/reflection/reflectionproperty/isprivate.xml @@ -27,6 +27,11 @@ &true; if the property is private, &false; otherwise. + + + Note this refers only to the main visibility, and not to a set-visibility, if specified. + + diff --git a/reference/reflection/reflectionproperty/isprotected.xml b/reference/reflection/reflectionproperty/isprotected.xml index 8732e9812354..c657791f5d3c 100644 --- a/reference/reflection/reflectionproperty/isprotected.xml +++ b/reference/reflection/reflectionproperty/isprotected.xml @@ -27,6 +27,11 @@ &true; if the property is protected, &false; otherwise. + + + Note this refers only to the main visibility, and not to a set-visibility, if specified. + + diff --git a/reference/reflection/reflectionproperty/ispublic.xml b/reference/reflection/reflectionproperty/ispublic.xml index 86480f9f6f50..85221d0f0f0f 100644 --- a/reference/reflection/reflectionproperty/ispublic.xml +++ b/reference/reflection/reflectionproperty/ispublic.xml @@ -25,8 +25,13 @@ &reftitle.returnvalues; - &true; if the property is public, &false; otherwise. + &true; if the property is marked public, &false; otherwise. + + + Note this refers only to the main visibility, and not to a set-visibility, if specified. + +