language/oop5/visibility.xml
c1f37a6c270aadbbb3da56a3973ffd62197adf2b
...
...
@@ -4,9 +4,9 @@
4
4
<title>Visibility</title>
5
5
<para>
6
6
The visibility of a property, a method or (as of PHP 7.1.0) a constant can be defined by prefixing
7
-
the declaration with the keywords <emphasis>public</emphasis>,
8
-
<emphasis>protected</emphasis> or
9
-
<emphasis>private</emphasis>. Class members declared public can be
7
+
the declaration with the keywords <literal>public</literal>,
8
+
<literal>protected</literal> or
9
+
<literal>private</literal>. Class members declared public can be
10
10
accessed everywhere. Members declared protected can be accessed
11
11
only within the class itself and by inheriting and parent
12
12
classes. Members declared as private may only be accessed by the
...
...
@@ -16,14 +16,13 @@
16
16
<sect2 xml:id="language.oop5.visibility-members">
17
17
<title>Property Visibility</title>
18
18
<para>
19
-
Class properties must be defined as public, private, or
20
-
protected. If declared using <emphasis>var</emphasis>,
21
-
the property will be defined as public.
19
+
Class properties may be defined as public, private, or
20
+
protected. Properties declared without any explicit visibility
21
+
keyword are defined as public.
22
22
</para>
23
-
<para>
24
-
<example>
25
-
<title>Property declaration</title>
26
-
<programlisting role="php">
23
+
<example>
24
+
<title>Property declaration</title>
25
+
<programlisting role="php" annotations="non-interactive">
27
26
<![CDATA[
28
27
<?php
29
28
/**
...
...
@@ -73,19 +72,137 @@ echo $obj2->protected; // Fatal Error
73
72
echo $obj2->private; // Undefined
74
73
$obj2->printHello(); // Shows Public2, Protected2, Undefined
75
74

75
+
?>
76
+
]]>
77
+
</programlisting>
78
+
</example>
79
+
<sect3 xml:id="language.oop5.visibility-members-aviz">
80
+
<title>Asymmetric Property Visibility</title>
81
+
<simpara>
82
+
As of PHP 8.4, properties may also have their
83
+
visibility set asymmetrically, with a different scope for
84
+
reading (<literal>get</literal>) and writing (<literal>set</literal>).
85
+
Specifically, the <literal>set</literal> visibility may be
86
+
specified separately, provided it is not more permissive than the
87
+
default visibility.
88
+
</simpara>
89
+
<example>
90
+
<title>Asymmetric Property visibility</title>
91
+
<programlisting role="php" annotations="non-interactive">
92
+
<![CDATA[
93
+
<?php
94
+
class Book
95
+
{
96
+
public function __construct(
97
+
public private(set) string $title,
98
+
public protected(set) string $author,
99
+
protected private(set) int $pubYear,
100
+
) {}
101
+
}
102
+

103
+
class SpecialBook extends Book
104
+
{
105
+
public function update(string $author, int $year): void
106
+
{
107
+
$this->author = $author; // OK
108
+
$this->pubYear = $year; // Fatal Error
109
+
}
110
+
}
111
+

112
+
$b = new Book('How to PHP', 'Peter H. Peterson', 2024);
113
+

114
+
echo $b->title; // Works
115
+
echo $b->author; // Works
116
+
echo $b->pubYear; // Fatal Error
117
+

118
+
$b->title = 'How not to PHP'; // Fatal Error
119
+
$b->author = 'Pedro H. Peterson'; // Fatal Error
120
+
$b->pubYear = 2023; // Fatal Error
76
121
?>
77
122
]]>
78
123
</programlisting>
79
124
</example>
80
-
</para>
81
-
<note>
125
+
<para>There are a few caveats regarding asymmetric visibility:</para>
126
+
<itemizedlist>
127
+
<listitem>
128
+
<simpara>
129
+
Only typed properties may have a separate <literal>set</literal> visibility.
130
+
</simpara>
131
+
</listitem>
132
+
<listitem>
133
+
<simpara>
134
+
The <literal>set</literal> visibility must be the same
135
+
as <literal>get</literal> or more restrictive. That is,
136
+
<code>public protected(set)</code> and <code>protected protected(set)</code>
137
+
are allowed, but <code>protected public(set)</code> will cause a syntax error.
138
+
</simpara>
139
+
</listitem>
140
+
<listitem>
141
+
<simpara>
142
+
If a property is <literal>public</literal>, then the main visibility may be
143
+
omitted. That is, <code>public private(set)</code> and <code>private(set)</code>
144
+
will have the same result.
145
+
</simpara>
146
+
</listitem>
147
+
<listitem>
148
+
<simpara>
149
+
A property with <literal>private(set)</literal> visibility
150
+
is automatically <literal>final</literal>, and may not be redeclared in a child class.
151
+
</simpara>
152
+
</listitem>
153
+
<listitem>
154
+
<simpara>
155
+
Obtaining a reference to a property follows <literal>set</literal> visibility, not <literal>get</literal>.
156
+
That is because a reference may be used to modify the property value.
157
+
</simpara>
158
+
</listitem>
159
+
<listitem>
160
+
<simpara>
161
+
Similarly, trying to write to an array property involves both a <literal>get</literal> and
162
+
<literal>set</literal> operation internally, and therefore will follow the <literal>set</literal>
163
+
visibility, as that is always the more restrictive.
164
+
</simpara>
165
+
</listitem>
166
+
</itemizedlist>
167
+
<note>
168
+
<simpara>
169
+
Spaces are not allowed in the set-visibility declaration.
170
+
<literal>private(set)</literal> is correct.
171
+
<literal>private( set )</literal> is not correct and will result in a parse error.
172
+
</simpara>
173
+
</note>
82
174
<simpara>
83
-
The PHP 4 method of declaring a variable with the
84
-
<emphasis>var</emphasis> keyword is still supported for compatibility
85
-
reasons (as a synonym for the public keyword). In PHP 5 before 5.1.3, its
86
-
usage would generate an <constant>E_STRICT</constant> warning.
175
+
When a class extends another, the child class may redefine
176
+
any property that is not <literal>final</literal>. When doing so,
177
+
it may widen either the main visibility or the <literal>set</literal>
178
+
visibility, provided that the new visibility is the same or wider
179
+
than the parent class. However, be aware that if a <literal>private</literal>
180
+
property is overridden, it does not actually change the parent's property
181
+
but creates a new property with a different internal name.
87
182
</simpara>
88
-
</note>
183
+
<example>
184
+
<title>Asymmetric Property inheritance</title>
185
+
<programlisting role="php" annotations="non-interactive">
186
+
<![CDATA[
187
+
<?php
188
+
class Book
189
+
{
190
+
protected string $title;
191
+
public protected(set) string $author;
192
+
protected private(set) int $pubYear;
193
+
}
194
+

195
+
class SpecialBook extends Book
196
+
{
197
+
public protected(set) $title; // OK, as reading is wider and writing the same.
198
+
public string $author; // OK, as reading is the same and writing is wider.
199
+
public protected(set) int $pubYear; // Fatal Error. private(set) properties are final.
200
+
}
201
+
?>
202
+
]]>
203
+
</programlisting>
204
+
</example>
205
+
</sect3>
89
206
</sect2>
90
207

91
208
<sect2 xml:id="language.oop5.visiblity-methods">
...
...
@@ -95,10 +212,9 @@ $obj2->printHello(); // Shows Public2, Protected2, Undefined
95
212
protected. Methods declared without any explicit visibility
96
213
keyword are defined as public.
97
214
</para>
98
-
<para>
99
-
<example>
100
-
<title>Method Declaration</title>
101
-
<programlisting role="php">
215
+
<example>
216
+
<title>Method Declaration</title>
217
+
<programlisting role="php" annotations="non-interactive">
102
218
<![CDATA[
103
219
<?php
104
220
/**
...
...
@@ -184,9 +300,8 @@ $myFoo->test(); // Bar::testPrivate
184
300
// Foo::testPublic
185
301
?>
186
302
]]>
187
-
</programlisting>
188
-
</example>
189
-
</para>
303
+
</programlisting>
304
+
</example>
190
305
</sect2>
191
306

192
307
<sect2 xml:id="language.oop5.visiblity-constants">
...
...
@@ -196,10 +311,9 @@ $myFoo->test(); // Bar::testPrivate
196
311
protected. Constants declared without any explicit visibility
197
312
keyword are defined as public.
198
313
</para>
199
-
<para>
200
-
<example>
201
-
<title>Constant Declaration as of PHP 7.1.0</title>
202
-
<programlisting role="php">
314
+
<example>
315
+
<title>Constant Declaration as of PHP 7.1.0</title>
316
+
<programlisting role="php" annotations="non-interactive">
203
317
<![CDATA[
204
318
<?php
205
319
/**
...
...
@@ -250,9 +364,8 @@ echo MyClass2::MY_PUBLIC; // Works
250
364
$myclass2->foo2(); // Public and Protected work, not Private
251
365
?>
252
366
]]>
253
-
</programlisting>
254
-
</example>
255
-
</para>
367
+
</programlisting>
368
+
</example>
256
369
</sect2>
257
370

258
371
<sect2 xml:id="language.oop5.visibility-other-objects">
...
...
@@ -265,7 +378,7 @@ $myclass2->foo2(); // Public and Protected work, not Private
265
378
</para>
266
379
<example>
267
380
<title>Accessing private members of the same object type</title>
268
-
<programlisting role="php">
381
+
<programlisting role="php" annotations="non-interactive">
269
382
<![CDATA[
270
383
<?php
271
384
class Test
...
...
@@ -309,7 +422,6 @@ Accessed the private method.
309
422
</example>
310
423
</sect2>
311
424
</sect1>
312
-
313
425
<!-- Keep this comment at the end of the file
314
426
Local variables:
315
427
mode: sgml
316
428