language/oop5/magic.xml
5e15a6c3e4d5819102361ae78e73c90a06238c8a
...
...
@@ -3,7 +3,19 @@
3
3
<sect1 xml:id="language.oop5.magic" xmlns="http://docbook.org/ns/docbook">
4
4
<title>Magic Methods</title>
5
5
<para>
6
-
The function names
6
+
Magic methods are special methods which override PHP's default's action
7
+
when certain actions are performed on an object.
8
+
</para>
9
+
<caution>
10
+
<simpara>
11
+
All methods names starting with <literal>__</literal> are reserved by PHP.
12
+
Therefore, it is not recommended to use such method names unless overriding
13
+
PHP's behavior.
14
+
</simpara>
15
+
</caution>
16
+
<para>
17
+
The following method names are considered magical:
18
+
<!-- Should be an itemized list ? -->
7
19
<link linkend="object.construct">__construct()</link>,
8
20
<link linkend="object.destruct">__destruct()</link>,
9
21
<link linkend="object.call">__call()</link>,
...
...
@@ -19,27 +31,38 @@
19
31
<link linkend="object.tostring">__toString()</link>,
20
32
<link linkend="object.invoke">__invoke()</link>,
21
33
<link linkend="object.set-state">__set_state()</link>,
22
-
<link linkend="object.clone">__clone()</link> and
23
-
<link linkend="object.debuginfo">__debugInfo()</link>
24
-
are magical in PHP classes. You
25
-
cannot have functions with these names in any of your
26
-
classes unless you want the magic functionality associated
27
-
with them.
34
+
<link linkend="object.clone">__clone()</link>, and
35
+
<link linkend="object.debuginfo">__debugInfo()</link>.
28
36
</para>
29
37

30
-
<note>
31
-
<simpara>
32
-
All magic methods <emphasis>MUST</emphasis> be declared as <literal>public</literal>
33
-
</simpara>
34
-
</note>
35
-

36
-
<caution>
38
+
<warning>
39
+
<!-- See for a code example of this behaviour: https://3v4l.org/Bov34 -->
37
40
<simpara>
38
-
PHP reserves all function names starting with __ as magical.
39
-
It is recommended that you do not use function names with
40
-
__ in PHP unless you want some documented magic functionality.
41
+
All magic methods, with the exception of
42
+
<link linkend="object.construct">__construct()</link>,
43
+
<link linkend="object.destruct">__destruct()</link>, and
44
+
<link linkend="object.clone">__clone()</link>,
45
+
<emphasis>must</emphasis> be declared as <literal>public</literal>,
46
+
otherwise an <constant>E_WARNING</constant> is emitted.
47
+
Prior to PHP 8.0.0, no diagnostic was emitted for the magic methods
48
+
<link linkend="object.sleep">__sleep()</link>,
49
+
<link linkend="object.wakeup">__wakeup()</link>,
50
+
<link linkend="object.serialize">__serialize()</link>,
51
+
<link linkend="object.unserialize">__unserialize()</link>, and
52
+
<link linkend="object.set-state">__set_state()</link>.
41
53
</simpara>
42
-
</caution>
54
+
</warning>
55
+
<warning>
56
+
<para>
57
+
If type declarations are used in the definition of a magic method, they
58
+
must be identical to the signature described in this document.
59
+
Otherwise, a fatal error is emitted.
60
+
Prior to PHP 8.0.0, no diagnostic was emitted.
61
+
However, <link linkend="object.construct">__construct()</link> and
62
+
<link linkend="object.destruct">__destruct()</link> must not declare a return type;
63
+
otherwise a fatal error is emitted.
64
+
</para>
65
+
</warning>
43
66
44
67
<sect2 xml:id="language.oop5.magic.sleep">
45
68
<title>
...
...
@@ -69,15 +92,19 @@
69
92
<para>
70
93
It is not possible for <link linkend="object.sleep">__sleep()</link> to return names of
71
94
private properties in parent classes. Doing this will result in an
72
-
<constant>E_NOTICE</constant> level error. Instead you may use the
73
-
<classname>Serializable</classname> interface.
95
+
<constant>E_NOTICE</constant> level error.
96
+
Use <link linkend="object.serialize">__serialize()</link> instead.
97
+
</para>
98
+
</note>
99
+
<note>
100
+
<para>
101
+
As of PHP 8.0.0, returning a value which is not an array from <link linkend="object.sleep">__sleep()</link> generates a warning. Previously, it generated a notice.
74
102
</para>
75
103
</note>
76
104
<para>
77
105
The intended use of <link linkend="object.sleep">__sleep()</link> is to commit pending
78
106
data or perform similar cleanup tasks. Also, the function is
79
-
useful if you have very large objects which do not need to be
80
-
saved completely.
107
+
useful if a very large object doesn't need to be saved completely.
81
108
</para>
82
109
<para>
83
110
Conversely, <function>unserialize</function> checks for the
...
...
@@ -181,7 +208,7 @@ class Connection
181
208
</note>
182
209
<note>
183
210
<para>
184
-
This feature is available since PHP 7.4.0.
211
+
This feature is available as of PHP 7.4.0.
185
212
</para>
186
213
</note>
187
214
<example>
...
...
@@ -239,15 +266,43 @@ class Connection
239
266
<para>
240
267
The <link linkend="object.tostring">__toString()</link> method allows a class to decide
241
268
how it will react when it is treated like a string. For example,
242
-
what <literal>echo $obj;</literal> will print. This method must
243
-
return a string, as otherwise a fatal <constant>E_RECOVERABLE_ERROR</constant>
244
-
level error is emitted.
269
+
what <literal>echo $obj;</literal> will print.
245
270
</para>
246
271
<warning>
272
+
<para>
273
+
As of PHP 8.0.0, the return value follows standard PHP type semantics,
274
+
meaning it will be coerced into a <type>string</type> if possible and if
275
+
<link linkend="language.types.declarations.strict">strict typing</link>
276
+
is disabled.
277
+
</para>
278
+
<para>
279
+
A <interfacename>Stringable</interfacename> object will
280
+
<emphasis>not</emphasis> be accepted by a <type>string</type> type declaration if
281
+
<link linkend="language.types.declarations.strict">strict typing</link>
282
+
is enabled. If such behaviour is wanted the type declaration must accept
283
+
<interfacename>Stringable</interfacename> and <type>string</type> via a union type.
284
+
</para>
285
+
<para>
286
+
As of PHP 8.0.0, any class that contains a <link linkend="object.tostring">__toString()</link>
287
+
method will also implicitly implement the <interfacename>Stringable</interfacename> interface, and will
288
+
thus pass type checks for that interface. Explicitly implementing the interface anyway is
289
+
recommended.
290
+
</para>
291
+
<para>
292
+
In PHP 7.4, the returned value <emphasis>must</emphasis> be a
293
+
<type>string</type>, otherwise an <classname>Error</classname> is thrown.
294
+
</para>
295
+
<para>
296
+
Prior to PHP 7.4.0, the returned value <emphasis>must</emphasis> be a
297
+
<type>string</type>, otherwise a fatal <constant>E_RECOVERABLE_ERROR</constant>
298
+
is emitted.
299
+
</para>
300
+
</warning>
301
+
<warning>
247
302
<simpara>
248
303
It was not possible to throw an exception from within a
249
-
<link linkend="object.tostring">__toString()</link> method before PHP 7.4.0. Doing so will
250
-
result in a fatal error.
304
+
<link linkend="object.tostring">__toString()</link>
305
+
method prior to PHP 7.4.0. Doing so will result in a fatal error.
251
306
</simpara>
252
307
</warning>
253
308
<example>
...
...
@@ -283,33 +338,18 @@ Hello
283
338
]]>
284
339
</screen>
285
340
</example>
286
-
<para>
287
-
It is worth noting that before PHP 5.2.0 the <link linkend="object.tostring">__toString()</link>
288
-
method was only called when it was directly combined with
289
-
<function>echo</function> or <function>print</function>.
290
-
Since PHP 5.2.0, it is called in any string context (e.g. in
291
-
<function>printf</function> with <literal>%s</literal> modifier) but not
292
-
in other types contexts (e.g. with <literal>%d</literal> modifier).
293
-
Since PHP 5.2.0, converting objects without <link linkend="object.tostring">__toString()</link>
294
-
method to string would cause <constant>E_RECOVERABLE_ERROR</constant>.
295
-
</para>
296
341
</sect2>
297
342

298
343
<sect2 xml:id="language.oop5.magic.invoke">
299
344
<title><link linkend="object.invoke">__invoke()</link></title>
300
345
<methodsynopsis xml:id="object.invoke">
301
346
<type>mixed</type><methodname>__invoke</methodname>
302
-
<methodparam choice="opt"><parameter>...</parameter></methodparam>
347
+
<methodparam rep="repeat"><parameter>values</parameter></methodparam>
303
348
</methodsynopsis>
304
349
<para>
305
350
The <link linkend="object.invoke">__invoke()</link> method is called when a script tries to
306
351
call an object as a function.
307
352
</para>
308
-
<note>
309
-
<para>
310
-
This feature is available since PHP 5.3.0.
311
-
</para>
312
-
</note>
313
353
<example>
314
354
<title>Using <link linkend="object.invoke">__invoke()</link></title>
315
355
<programlisting role="php">
...
...
@@ -336,6 +376,96 @@ bool(true)
336
376
]]>
337
377
</screen>
338
378
</example>
379
+
<example>
380
+
<title>Using <link linkend="object.invoke">__invoke()</link></title>
381
+
<programlisting role="php">
382
+
<![CDATA[
383
+
<?php
384
+
class Sort
385
+
{
386
+
private $key;
387
+

388
+
public function __construct(string $key)
389
+
{
390
+
$this->key = $key;
391
+
}
392
+

393
+
public function __invoke(array $a, array $b): int
394
+
{
395
+
return $a[$this->key] <=> $b[$this->key];
396
+
}
397
+
}
398
+

399
+
$customers = [
400
+
['id' => 1, 'first_name' => 'John', 'last_name' => 'Do'],
401
+
['id' => 3, 'first_name' => 'Alice', 'last_name' => 'Gustav'],
402
+
['id' => 2, 'first_name' => 'Bob', 'last_name' => 'Filipe']
403
+
];
404
+

405
+
// sort customers by first name
406
+
usort($customers, new Sort('first_name'));
407
+
print_r($customers);
408
+

409
+
// sort customers by last name
410
+
usort($customers, new Sort('last_name'));
411
+
print_r($customers);
412
+
?>
413
+
]]>
414
+
</programlisting>
415
+
&example.outputs;
416
+
<screen>
417
+
<![CDATA[
418
+
Array
419
+
(
420
+
[0] => Array
421
+
(
422
+
[id] => 3
423
+
[first_name] => Alice
424
+
[last_name] => Gustav
425
+
)
426
+

427
+
[1] => Array
428
+
(
429
+
[id] => 2
430
+
[first_name] => Bob
431
+
[last_name] => Filipe
432
+
)
433
+

434
+
[2] => Array
435
+
(
436
+
[id] => 1
437
+
[first_name] => John
438
+
[last_name] => Do
439
+
)
440
+

441
+
)
442
+
Array
443
+
(
444
+
[0] => Array
445
+
(
446
+
[id] => 1
447
+
[first_name] => John
448
+
[last_name] => Do
449
+
)
450
+

451
+
[1] => Array
452
+
(
453
+
[id] => 2
454
+
[first_name] => Bob
455
+
[last_name] => Filipe
456
+
)
457
+

458
+
[2] => Array
459
+
(
460
+
[id] => 3
461
+
[first_name] => Alice
462
+
[last_name] => Gustav
463
+
)
464
+

465
+
)
466
+
]]>
467
+
</screen>
468
+
</example>
339
469
</sect2>
340
470

341
471
<sect2 xml:id="language.oop5.magic.set-state">
...
...
@@ -346,14 +476,14 @@ bool(true)
346
476
</methodsynopsis>
347
477
<para>
348
478
This <link linkend="language.oop5.static">static</link> method is called
349
-
for classes exported by <function>var_export</function> since PHP 5.1.0.
479
+
for classes exported by <function>var_export</function>.
350
480
</para>
351
481
<para>
352
482
The only parameter of this method is an array containing exported
353
-
properties in the form <literal>array('property' => value, ...)</literal>.
483
+
properties in the form <literal>['property' => value, ...]</literal>.
354
484
</para>
355
485
<example>
356
-
<title>Using <link linkend="object.set-state">__set_state()</link> (since PHP 5.1.0)</title>
486
+
<title>Using <link linkend="object.set-state">__set_state()</link></title>
357
487
<programlisting role="php">
358
488
<![CDATA[
359
489
<?php
...
...
@@ -363,7 +493,7 @@ class A
363
493
public $var1;
364
494
public $var2;
365
495

366
-
public static function __set_state($an_array) // As of PHP 5.1.0
496
+
public static function __set_state($an_array)
367
497
{
368
498
$obj = new A;
369
499
$obj->var1 = $an_array['var1'];
...
...
@@ -376,18 +506,20 @@ $a = new A;
376
506
$a->var1 = 5;
377
507
$a->var2 = 'foo';
378
508

379
-
eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
380
-
// 'var1' => 5,
381
-
// 'var2' => 'foo',
382
-
// ));
509
+
$b = var_export($a, true);
383
510
var_dump($b);
384
-

511
+
eval('$c = ' . $b . ';');
512
+
var_dump($c);
385
513
?>
386
514
]]>
387
515
</programlisting>
388
516
&example.outputs;
389
517
<screen>
390
518
<![CDATA[
519
+
string(60) "A::__set_state(array(
520
+
'var1' => 5,
521
+
'var2' => 'foo',
522
+
))"
391
523
object(A)#2 (2) {
392
524
["var1"]=>
393
525
int(5)
...
...
@@ -401,7 +533,7 @@ object(A)#2 (2) {
401
533
<simpara>
402
534
When exporting an object, <function>var_export</function> does not check
403
535
whether <link linkend="object.set-state">__set_state()</link> is
404
-
implemented by the object's class, so re-importing such objects will fail,
536
+
implemented by the object's class, so re-importing objects will result in an <classname>Error</classname> exception,
405
537
if __set_state() is not implemented. Particularly, this affects some
406
538
internal classes.
407
539
</simpara>
...
...
@@ -424,9 +556,6 @@ object(A)#2 (2) {
424
556
defined on an object, then all public, protected and private properties
425
557
will be shown.
426
558
</para>
427
-
<para>
428
-
This feature was added in PHP 5.6.0.
429
-
</para>
430
559
<example>
431
560
<title>Using <link linkend="object.debuginfo">__debugInfo()</link></title>
432
561
<programlisting role="php">
...
...
@@ -462,7 +591,6 @@ object(C)#1 (1) {
462
591
</example>
463
592
</sect2>
464
593
</sect1>
465
-
466
594
<!-- Keep this comment at the end of the file
467
595
Local variables:
468
596
mode: sgml
469
597