language/oop5/properties.xml
ba65e0f4f7f28bb29b42362c38d60e41970bdfe6
...
...
@@ -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>
47
+
<title>Property declarations</title>
64
48
<programlisting role="php">
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,276 @@ 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 <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
+
<example>
258
+
<programlisting role="php">
259
+
<![CDATA[
260
+
<?php
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
+
</example>
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
+
<example>
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
+
}
175
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
+
</example>
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
+
<example>
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
+
</example>
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>
176
352
<!-- Keep this comment at the end of the file
177
353
Local variables:
178
354
mode: sgml
179
355