language/oop5/properties.xml
f94d903985119d3ac00f4528551df947f57b667f
...
...
@@ -4,85 +4,72 @@
4
4
<title>Properties</title>
5
5

6
6
<para>
7
-
Class member variables are called "properties". You may also see
8
-
them referred to using other terms such as "attributes" or
9
-
"fields", but for the purposes of this reference we will use
10
-
"properties". They are defined by using one of the
11
-
keywords <literal>public</literal>, <literal>protected</literal>,
12
-
or <literal>private</literal>, followed by a normal variable
13
-
declaration. This declaration may include an initialization, but
14
-
this initialization must be a constant value--that is, it must be
15
-
able to be evaluated at compile time and must not depend on
16
-
run-time information in order to be evaluated.
17
-
</para>
18
-
<para>
19
-
See <xref linkend="language.oop5.visibility" /> for more
20
-
information on the meanings
21
-
of <literal>public</literal>, <literal>protected</literal>,
22
-
and <literal>private</literal>.
7
+
Class member variables are called <emphasis>properties</emphasis>.
8
+
They may be referred to using other terms such as <emphasis>fields</emphasis>,
9
+
but for the purposes of this reference <emphasis>properties</emphasis>
10
+
will be used. They are defined by using at least one modifier (such as
11
+
<xref linkend="language.oop5.visibility"/>,
12
+
<xref linkend="language.oop5.static"/>,
13
+
or, as of PHP 8.1.0, <link linkend="language.oop5.properties.readonly-properties">readonly</link>),
14
+
optionally (except for <code>readonly</code> properties), as of PHP 7.4,
15
+
followed by a type declaration, followed by a normal variable declaration.
16
+
This declaration may include an initialization, but this initialization
17
+
must be a <link linkend="language.constants">constant</link> value.
23
18
</para>
24
19
<note>
25
20
<para>
26
-
In order to maintain backward compatibility with PHP 4, PHP 5 will
27
-
still accept the use of the keyword <literal>var</literal> in
28
-
property declarations instead of (or in addition
29
-
to) <literal>public</literal>, <literal>protected</literal>,
30
-
or <literal>private</literal>. However, <literal>var</literal> is
31
-
no longer required. In versions of PHP from 5.0 to 5.1.3, the use
32
-
of <literal>var</literal> was considered deprecated and would
33
-
issue an <constant>E_STRICT</constant> warning, but since PHP
34
-
5.1.3 it is no longer deprecated and does not issue the warning.
35
-
</para>
36
-
<para>
37
-
If you declare a property using <literal>var</literal> instead of
38
-
one of <literal>public</literal>, <literal>protected</literal>,
39
-
or <literal>private</literal>, then PHP 5 will treat the property
40
-
as if it had been declared as <literal>public</literal>.
21
+
An obsolete way of declaring class properties, is by using the
22
+
<literal>var</literal> keyword instead of a modifier.
41
23
</para>
42
24
</note>
25
+
<note>
26
+
<simpara>
27
+
A property declared without a <xref linkend="language.oop5.visibility"/>
28
+
modifier will be declared as <literal>public</literal>.
29
+
</simpara>
30
+
</note>
43
31
<para>
44
32
Within class methods non-static properties may be accessed by using
45
33
<literal>-&gt;</literal> (Object Operator): <varname>$this-&gt;property</varname>
46
34
(where <literal>property</literal> is the name of the property).
47
35
Static properties are accessed by using the <literal>::</literal> (Double Colon):
48
-
<varname>self::$property</varname>. See <link linkend="language.oop5.static">Static Keyword</link>
36
+
<varname>self::$property</varname>. See <xref linkend="language.oop5.static" />
49
37
for more information on the difference between static and non-static properties.
50
38
</para>
51
39
<para>
52
40
The pseudo-variable <varname>$this</varname> is available inside
53
-
any class method when that method is called from within an object
54
-
context. <varname>$this</varname> is a reference to the calling
55
-
object (usually the object to which the method belongs, but
56
-
possibly another object, if the method is called
57
-
<link linkend="language.oop5.static">statically</link> from the context
58
-
of a secondary object).
41
+
any class method when that method is called from within an object context.
42
+
<varname>$this</varname> is the value of the calling object.
59
43
</para>
60
44

61
45
<para>
62
46
<example>
63
-
<title>property declarations</title>
47
+
<title>Property declarations</title>
64
48
<programlisting role="php">
65
49
<![CDATA[
66
50
<?php
67
51
class SimpleClass
68
52
{
69
-
// invalid property declarations:
70
53
public $var1 = 'hello ' . 'world';
71
54
public $var2 = <<<EOD
72
55
hello world
73
56
EOD;
74
57
public $var3 = 1+2;
58
+
// invalid property declarations:
75
59
public $var4 = self::myStaticMethod();
76
60
public $var5 = $myVar;
77
61

78
62
// valid property declarations:
79
63
public $var6 = myConstant;
80
-
public $var7 = array(true, false);
64
+
public $var7 = [true, false];
81
65

82
-
// This is allowed only in PHP 5.3.0 and later.
83
66
public $var8 = <<<'EOD'
84
67
hello world
85
68
EOD;
69
+

70
+
// Without visibility modifier:
71
+
static $var9;
72
+
readonly int $var10;
86
73
}
87
74
?>
88
75
]]>
...
...
@@ -92,41 +79,276 @@ EOD;
92
79

93
80
<note>
94
81
<para>
95
-
There are some nice functions to handle classes and objects. You
96
-
might want to take a look at
97
-
the <link linkend="ref.classobj">Class/Object Functions</link>.
82
+
There are various functions to handle classes and objects.
83
+
See the <link linkend="ref.classobj">Class/Object Functions</link>
84
+
reference.
98
85
</para>
99
86
</note>
100
87

101
-
<para>
102
-
Unlike
103
-
<link linkend="language.types.string.syntax.heredoc">heredocs</link>,
104
-
<link linkend="language.types.string.syntax.nowdoc">nowdocs</link>
105
-
can be used in any static data context, including property
106
-
declarations.
107
-
<example>
108
-
<title>Example of using a nowdoc to initialize a property</title>
109
-
<programlisting role="php">
88
+
<sect2 xml:id="language.oop5.properties.typed-properties">
89
+
<title>Type declarations</title>
90
+
<para>
91
+
As of PHP 7.4.0, property definitions can include
92
+
<xref linkend="language.types.declarations" />,
93
+
with the exception of <type>callable</type>.
94
+
<example>
95
+
<title>Example of typed properties</title>
96
+
<programlisting role="php">
110
97
<![CDATA[
111
98
<?php
112
-
class foo {
113
-
// As of PHP 5.3.0
114
-
public $bar = <<<'EOT'
115
-
bar
116
-
EOT;
99
+

100
+
class User
101
+
{
102
+
public int $id;
103
+
public ?string $name;
104
+

105
+
public function __construct(int $id, ?string $name)
106
+
{
107
+
$this->id = $id;
108
+
$this->name = $name;
109
+
}
117
110
}
111
+

112
+
$user = new User(1234, null);
113
+

114
+
var_dump($user->id);
115
+
var_dump($user->name);
116
+

118
117
?>
119
118
]]>
120
-
</programlisting>
121
-
</example>
122
-
</para>
123
-
<note>
119
+
</programlisting>
120
+
&example.outputs;
121
+
<screen>
122
+
<![CDATA[
123
+
int(1234)
124
+
NULL
125
+
]]>
126
+
</screen>
127
+
</example>
128
+
</para>
129
+

124
130
<para>
125
-
Nowdoc support was added in PHP 5.3.0.
131
+
Typed properties must be initialized before accessing, otherwise an
132
+
<classname>Error</classname> is thrown.
133
+
<example>
134
+
<title>Accessing properties</title>
135
+
<programlisting role="php">
136
+
<![CDATA[
137
+
<?php
138
+

139
+
class Shape
140
+
{
141
+
public int $numberOfSides;
142
+
public string $name;
143
+

144
+
public function setNumberOfSides(int $numberOfSides): void
145
+
{
146
+
$this->numberOfSides = $numberOfSides;
147
+
}
148
+

149
+
public function setName(string $name): void
150
+
{
151
+
$this->name = $name;
152
+
}
153
+

154
+
public function getNumberOfSides(): int
155
+
{
156
+
return $this->numberOfSides;
157
+
}
158
+

159
+
public function getName(): string
160
+
{
161
+
return $this->name;
162
+
}
163
+
}
164
+

165
+
$triangle = new Shape();
166
+
$triangle->setName("triangle");
167
+
$triangle->setNumberofSides(3);
168
+
var_dump($triangle->getName());
169
+
var_dump($triangle->getNumberOfSides());
170
+

171
+
$circle = new Shape();
172
+
$circle->setName("circle");
173
+
var_dump($circle->getName());
174
+
var_dump($circle->getNumberOfSides());
175
+
?>
176
+
]]>
177
+
</programlisting>
178
+
&example.outputs;
179
+
<screen>
180
+
<![CDATA[
181
+
string(8) "triangle"
182
+
int(3)
183
+
string(6) "circle"
184
+

185
+
Fatal error: Uncaught Error: Typed property Shape::$numberOfSides must not be accessed before initialization
186
+
]]>
187
+
</screen>
188
+
</example>
126
189
</para>
127
-
</note>
128
-
</sect1>
190
+
</sect2>
191
+

192
+
<sect2 xml:id="language.oop5.properties.readonly-properties">
193
+
<title>Readonly properties</title>
194
+
<para>
195
+
As of PHP 8.1.0, a property can be declared with the <code>readonly</code> modifier, which prevents modification of the property after initialization.
196
+
<example>
197
+
<title>Example of readonly properties</title>
198
+
<programlisting role="php">
199
+
<![CDATA[
200
+
<?php
201
+

202
+
class Test {
203
+
public readonly string $prop;
204
+

205
+
public function __construct(string $prop) {
206
+
// Legal initialization.
207
+
$this->prop = $prop;
208
+
}
209
+
}
210
+

211
+
$test = new Test("foobar");
212
+
// Legal read.
213
+
var_dump($test->prop); // string(6) "foobar"
214
+

215
+
// Illegal reassignment. It does not matter that the assigned value is the same.
216
+
$test->prop = "foobar";
217
+
// Error: Cannot modify readonly property Test::$prop
218
+
?>
219
+
]]>
220
+
</programlisting>
221
+
</example>
222
+
<note>
223
+
<para>
224
+
The readonly modifier can only be applied to <link linkend="language.oop5.properties.typed-properties">typed properties</link>.
225
+
A readonly property without type constraints can be created using the <xref linkend="language.types.mixed"/> type.
226
+
</para>
227
+
</note>
228
+
<note>
229
+
<para>
230
+
Readonly static properties are not supported.
231
+
</para>
232
+
</note>
233
+
</para>
234
+
<para>
235
+
A readonly property can only be initialized once, and only from the scope where it has been declared. Any other assignment or modification of the property will result in an <classname>Error</classname> exception.
236
+
<example>
237
+
<title>Illegal initialization of readonly properties</title>
238
+
<programlisting role="php">
239
+
<![CDATA[
240
+
<?php
241
+
class Test1 {
242
+
public readonly string $prop;
243
+
}
244
+

245
+
$test1 = new Test1;
246
+
// Illegal initialization outside of private scope.
247
+
$test1->prop = "foobar";
248
+
// Error: Cannot initialize readonly property Test1::$prop from global scope
249
+
?>
250
+
]]>
251
+
</programlisting>
252
+
</example>
253
+
</para>
254
+
<note>
255
+
<para>
256
+
Specifying an explicit default value on readonly properties is not allowed, because a readonly property with a default value is essentially the same as a constant, and thus not particularly useful.
257
+
<informalexample>
258
+
<programlisting role="php">
259
+
<![CDATA[
260
+
<?php
129
261

262
+
class Test {
263
+
// Fatal error: Readonly property Test::$prop cannot have default value
264
+
public readonly int $prop = 42;
265
+
}
266
+
?>
267
+
]]>
268
+
</programlisting>
269
+
</informalexample>
270
+
</para>
271
+
</note>
272
+
<note>
273
+
<para>
274
+
Readonly properties cannot be <function>unset</function> once they are initialized. However, it is possible to unset a readonly property prior to initialization, from the scope where the property has been declared.
275
+
</para>
276
+
</note>
277
+
<para>
278
+
Modifications are not necessarily plain assignments, all of the following will also result in an <classname>Error</classname> exception:
279
+
<informalexample>
280
+
<programlisting role="php">
281
+
<![CDATA[
282
+
<?php
283
+

284
+
class Test {
285
+
public function __construct(
286
+
public readonly int $i = 0,
287
+
public readonly array $ary = [],
288
+
) {}
289
+
}
290
+

291
+
$test = new Test;
292
+
$test->i += 1;
293
+
$test->i++;
294
+
++$test->i;
295
+
$test->ary[] = 1;
296
+
$test->ary[0][] = 1;
297
+
$ref =& $test->i;
298
+
$test->i =& $ref;
299
+
byRef($test->i);
300
+
foreach ($test as &$prop);
301
+
?>
302
+
]]>
303
+
</programlisting>
304
+
</informalexample>
305
+
</para>
306
+
<para>
307
+
However, readonly properties do not preclude interior mutability. Objects (or resources) stored in readonly properties may still be modified internally:
308
+
<informalexample>
309
+
<programlisting role="php">
310
+
<![CDATA[
311
+
<?php
312
+

313
+
class Test {
314
+
public function __construct(public readonly object $obj) {}
315
+
}
316
+

317
+
$test = new Test(new stdClass);
318
+
// Legal interior mutation.
319
+
$test->obj->foo = 1;
320
+
// Illegal reassignment.
321
+
$test->obj = new stdClass;
322
+
?>
323
+
]]>
324
+
</programlisting>
325
+
</informalexample>
326
+
</para>
327
+
</sect2>
328
+

329
+
<sect2 xml:id="language.oop5.properties.dynamic-properties">
330
+
<title>Dynamic properties</title>
331
+
<para>
332
+
If trying to assign to a non-existent property on an &object;,
333
+
PHP will automatically create a corresponding property.
334
+
This dynamically created property will <emphasis>only</emphasis> be
335
+
available on this class instance.
336
+
</para>
337
+

338
+
<warning>
339
+
<simpara>
340
+
Dynamic properties are deprecated as of PHP 8.2.0.
341
+
It is recommended to declare the property instead.
342
+
To handle arbitrary property names, the class should implement the magic
343
+
methods <link linkend="object.get">__get()</link> and
344
+
<link linkend="object.set">__set()</link>.
345
+
At last resort the class can be marked with the
346
+
<code>#[\AllowDynamicProperties]</code> attribute.
347
+
</simpara>
348
+
</warning>
349
+
</sect2>
350
+

351
+
</sect1>
130
352
<!-- Keep this comment at the end of the file
131
353
Local variables:
132
354
mode: sgml
133
355