language/oop5/properties.xml
c1f37a6c270aadbbb3da56a3973ffd62197adf2b
...
...
@@ -4,75 +4,56 @@
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>, optionally followed by a type declaration,
13
-
followed by a normal variable declaration. This declaration may
14
-
include an initialization, but this initialization must be a constant
15
-
value--that is, it must be able to be evaluated at compile time and
16
-
must not depend on 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>
64
-
<programlisting role="php">
47
+
<title>Property declarations</title>
48
+
<programlisting role="php" annotations="non-interactive">
65
49
<![CDATA[
66
50
<?php
67
51
class SimpleClass
68
52
{
69
-
// valid as of PHP 5.6.0:
70
53
public $var1 = 'hello ' . 'world';
71
-
// valid as of PHP 5.3.0:
72
54
public $var2 = <<<EOD
73
55
hello world
74
56
EOD;
75
-
// valid as of PHP 5.6.0:
76
57
public $var3 = 1+2;
77
58
// invalid property declarations:
78
59
public $var4 = self::myStaticMethod();
...
...
@@ -80,12 +61,15 @@ EOD;
80
61

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

85
-
// valid as of PHP 5.3.0:
86
66
public $var8 = <<<'EOD'
87
67
hello world
88
68
EOD;
69
+

70
+
// Without visibility modifier:
71
+
static $var9;
72
+
readonly int $var10;
89
73
}
90
74
?>
91
75
]]>
...
...
@@ -95,84 +79,312 @@ EOD;
95
79

96
80
<note>
97
81
<para>
98
-
There are some nice functions to handle classes and objects. You
99
-
might want to take a look at
100
-
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.
101
85
</para>
102
86
</note>
103
87

104
-
<para>
105
-
As of PHP 5.3.0
106
-
<link linkend="language.types.string.syntax.heredoc">heredocs</link> and
107
-
<link linkend="language.types.string.syntax.nowdoc">nowdocs</link>
108
-
can be used in any static data context, including property
109
-
declarations.
110
-
<example>
111
-
<title>Example of using a nowdoc to initialize a property</title>
112
-
<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">
113
97
<![CDATA[
114
98
<?php
115
-
class foo {
116
-
// As of PHP 5.3.0
117
-
public $bar = <<<'EOT'
118
-
bar
119
-
EOT;
120
-
public $baz = <<<EOT
121
-
baz
122
-
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
+
}
123
110
}
111
+

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

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

124
117
?>
125
118
]]>
126
-
</programlisting>
127
-
</example>
128
-
</para>
129
-
<note>
130
-
<para>
131
-
Nowdoc and Heredoc support was added in PHP 5.3.0.
119
+
</programlisting>
120
+
&example.outputs;
121
+
<screen>
122
+
<![CDATA[
123
+
int(1234)
124
+
NULL
125
+
]]>
126
+
</screen>
127
+
</example>
132
128
</para>
133
-
</note>
134
129

135
-
<para>
136
-
As of PHP 7.4.0, property definitions can include a type declaration, with the exception of
137
-
the <literal>callable</literal> type.
138
-
<example>
139
-
<title>Example of typed properties</title>
140
-
<programlisting role="php">
130
+
<para>
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">
141
136
<![CDATA[
142
137
<?php
143
138

144
-
class User
139
+
class Shape
145
140
{
146
-
public int $id;
141
+
public int $numberOfSides;
147
142
public string $name;
148
143

149
-
public function __construct(int $id, string $name)
144
+
public function setNumberOfSides(int $numberOfSides): void
145
+
{
146
+
$this->numberOfSides = $numberOfSides;
147
+
}
148
+

149
+
public function setName(string $name): void
150
150
{
151
-
$this->id = $id;
152
151
$this->name = $name;
153
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
+
}
154
163
}
155
164

156
-
$user = new User(1234, "php");
157
-
echo "ID: " . $user->id;
158
-
echo "\n";
159
-
echo "Name: " . $user->name;
165
+
$triangle = new Shape();
166
+
$triangle->setName("triangle");
167
+
$triangle->setNumberofSides(3);
168
+
var_dump($triangle->getName());
169
+
var_dump($triangle->getNumberOfSides());
160
170

171
+
$circle = new Shape();
172
+
$circle->setName("circle");
173
+
var_dump($circle->getName());
174
+
var_dump($circle->getNumberOfSides());
161
175
?>
162
176
]]>
163
-
</programlisting>
164
-
&example.outputs;
165
-
<screen>
177
+
</programlisting>
178
+
&example.outputs;
179
+
<screen>
166
180
<![CDATA[
167
-
ID: 1234
168
-
Name: php
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
169
186
]]>
170
-
</screen>
171
-
</example>
172
-
</para>
187
+
</screen>
188
+
</example>
189
+
</para>
190
+
</sect2>
173
191

174
-
</sect1>
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 <literal>readonly</literal> modifier,
196
+
which prevents modification of the property after initialization. Prior to PHP 8.4.0
197
+
a <literal>readonly</literal> property is implicitly private-set, and may only be written to
198
+
from the same class. As of PHP 8.4.0, <literal>readonly</literal> properties are implicitly
199
+
<link linkend="language.oop5.visibility-members-aviz"><literal>protected(set)</literal></link>,
200
+
so may be set from child classes. That may be overridden
201
+
explicitly if desired.
202
+
<example>
203
+
<title>Example of readonly properties</title>
204
+
<programlisting role="php" annotations="non-interactive">
205
+
<![CDATA[
206
+
<?php
207
+

208
+
class Test {
209
+
public readonly string $prop;
210
+

211
+
public function __construct(string $prop) {
212
+
// Legal initialization.
213
+
$this->prop = $prop;
214
+
}
215
+
}
216
+

217
+
$test = new Test("foobar");
218
+
// Legal read.
219
+
var_dump($test->prop); // string(6) "foobar"
220
+

221
+
// Illegal reassignment. It does not matter that the assigned value is the same.
222
+
$test->prop = "foobar";
223
+
// Error: Cannot modify readonly property Test::$prop
224
+
?>
225
+
]]>
226
+
</programlisting>
227
+
</example>
228
+
<note>
229
+
<para>
230
+
The readonly modifier can only be applied to <link linkend="language.oop5.properties.typed-properties">typed properties</link>.
231
+
A readonly property without type constraints can be created using the <xref linkend="language.types.mixed"/> type.
232
+
</para>
233
+
</note>
234
+
<note>
235
+
<para>
236
+
Readonly static properties are not supported.
237
+
</para>
238
+
</note>
239
+
</para>
240
+
<para>
241
+
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.
242
+
<example>
243
+
<title>Illegal initialization of readonly properties</title>
244
+
<programlisting role="php" annotations="non-interactive">
245
+
<![CDATA[
246
+
<?php
247
+
class Test1 {
248
+
public readonly string $prop;
249
+
}
250
+

251
+
$test1 = new Test1;
252
+
// Illegal initialization outside of private scope.
253
+
$test1->prop = "foobar";
254
+
// Error: Cannot initialize readonly property Test1::$prop from global scope
255
+
?>
256
+
]]>
257
+
</programlisting>
258
+
</example>
259
+
</para>
260
+
<note>
261
+
<para>
262
+
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.
263
+
<informalexample>
264
+
<programlisting role="php" annotations="non-interactive">
265
+
<![CDATA[
266
+
<?php
267
+

268
+
class Test {
269
+
// Fatal error: Readonly property Test::$prop cannot have default value
270
+
public readonly int $prop = 42;
271
+
}
272
+
?>
273
+
]]>
274
+
</programlisting>
275
+
</informalexample>
276
+
</para>
277
+
</note>
278
+
<note>
279
+
<para>
280
+
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.
281
+
</para>
282
+
</note>
283
+
<para>
284
+
Modifications are not necessarily plain assignments, all of the following will also result in an <classname>Error</classname> exception:
285
+
<informalexample>
286
+
<programlisting role="php" annotations="non-interactive">
287
+
<![CDATA[
288
+
<?php
289
+

290
+
class Test {
291
+
public function __construct(
292
+
public readonly int $i = 0,
293
+
public readonly array $ary = [],
294
+
) {}
295
+
}
296
+

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

319
+
class Test {
320
+
public function __construct(public readonly object $obj) {}
321
+
}
322
+

323
+
$test = new Test(new stdClass);
324
+
// Legal interior mutation.
325
+
$test->obj->foo = 1;
326
+
// Illegal reassignment.
327
+
$test->obj = new stdClass;
328
+
?>
329
+
]]>
330
+
</programlisting>
331
+
</informalexample>
332
+
</para>
333
+
<para>
334
+
As of PHP 8.3.0, readonly properties can be reinitialized when cloning an object
335
+
using the <link linkend="object.clone">__clone()</link> method.
336
+
<example>
337
+
<title>Readonly properties and cloning</title>
338
+
<programlisting role="php">
339
+
<![CDATA[
340
+
<?php
341
+
class Test1 {
342
+
public readonly ?string $prop;
343
+

344
+
public function __clone() {
345
+
$this->prop = null;
346
+
}
347
+

348
+
public function setProp(string $prop): void {
349
+
$this->prop = $prop;
350
+
}
351
+
}
352
+

353
+
$test1 = new Test1;
354
+
$test1->setProp('foobar');
355
+

356
+
$test2 = clone $test1;
357
+
var_dump($test2->prop); // NULL
358
+
?>
359
+
]]>
360
+
</programlisting>
361
+
</example>
362
+
</para>
363
+
</sect2>
175
364

365
+
<sect2 xml:id="language.oop5.properties.dynamic-properties">
366
+
<title>Dynamic properties</title>
367
+
<para>
368
+
If trying to assign to a non-existent property on an &object;,
369
+
PHP will automatically create a corresponding property.
370
+
This dynamically created property will <emphasis>only</emphasis> be
371
+
available on this class instance.
372
+
</para>
373
+

374
+
<warning>
375
+
<simpara>
376
+
Dynamic properties are deprecated as of PHP 8.2.0.
377
+
It is recommended to declare the property instead.
378
+
To handle arbitrary property names, the class should implement the magic
379
+
methods <link linkend="object.get">__get()</link> and
380
+
<link linkend="object.set">__set()</link>.
381
+
At last resort the class can be marked with the
382
+
<code>#[\AllowDynamicProperties]</code> attribute.
383
+
</simpara>
384
+
</warning>
385
+
</sect2>
386
+

387
+
</sect1>
176
388
<!-- Keep this comment at the end of the file
177
389
Local variables:
178
390
mode: sgml
179
391