language/oop5/traits.xml
c1f37a6c270aadbbb3da56a3973ffd62197adf2b
...
...
@@ -3,7 +3,7 @@
3
3
<sect1 xml:id="language.oop5.traits" xmlns="http://docbook.org/ns/docbook">
4
4
<title>Traits</title>
5
5
<para>
6
-
As of PHP 5.4.0, PHP implements a method of code reuse called Traits.
6
+
PHP implements a way to reuse code called Traits.
7
7
</para>
8
8
<para>
9
9
Traits are a mechanism for code reuse in single inheritance languages such as
...
...
@@ -25,23 +25,43 @@
25
25
<programlisting role="php">
26
26
<![CDATA[
27
27
<?php
28
-
trait ezcReflectionReturnInfo {
29
-
function getReturnType() { /*1*/ }
30
-
function getReturnDescription() { /*2*/ }
28
+

29
+
trait TraitA {
30
+
public function sayHello() {
31
+
echo 'Hello';
32
+
}
31
33
}
32
34

33
-
class ezcReflectionMethod extends ReflectionMethod {
34
-
use ezcReflectionReturnInfo;
35
-
/* ... */
35
+
trait TraitB {
36
+
public function sayWorld() {
37
+
echo 'World';
38
+
}
36
39
}
37
40

38
-
class ezcReflectionFunction extends ReflectionFunction {
39
-
use ezcReflectionReturnInfo;
40
-
/* ... */
41
+
class MyHelloWorld
42
+
{
43
+
use TraitA, TraitB; // A class can use multiple traits
44
+

45
+
public function sayHelloWorld() {
46
+
$this->sayHello();
47
+
echo ' ';
48
+
$this->sayWorld();
49
+
echo "!\n";
50
+
}
41
51
}
52
+

53
+
$myHelloWorld = new MyHelloWorld();
54
+
$myHelloWorld->sayHelloWorld();
55
+

42
56
?>
43
57
]]>
44
58
</programlisting>
59
+
&example.outputs;
60
+
<screen>
61
+
<![CDATA[
62
+
Hello World!
63
+
]]>
64
+
</screen>
45
65
</example>
46
66

47
67
<sect2 xml:id="language.oop5.traits.precedence">
...
...
@@ -127,7 +147,7 @@ Hello Universe!
127
147
<sect2 xml:id="language.oop5.traits.multiple">
128
148
<title>Multiple Traits</title>
129
149
<para>
130
-
Multiple Traits can be inserted into a class by listing them in the use
150
+
Multiple Traits can be inserted into a class by listing them in the <literal>use</literal>
131
151
statement, separated by commas.
132
152
</para>
133
153
<example xml:id="language.oop5.traits.multiple.ex1">
...
...
@@ -200,7 +220,7 @@ Hello World!
200
220
to be able to use B's bigTalk implementation under an additional alias
201
221
<literal>talk</literal>.
202
222
</para>
203
-
<programlisting role="php">
223
+
<programlisting role="php" annotations="non-interactive">
204
224
<![CDATA[
205
225
<?php
206
226
trait A {
...
...
@@ -239,13 +259,6 @@ class Aliased_Talker {
239
259
]]>
240
260
</programlisting>
241
261
</example>
242
-
<note>
243
-
<para>
244
-
Prior to PHP 7.0, defining a property in a class with the same name as in a trait
245
-
would throw an <constant>E_STRICT</constant> if the class definition was compatible
246
-
(same visibility and initial value).
247
-
</para>
248
-
</note>
249
262
</sect2>
250
263

251
264
<sect2 xml:id="language.oop5.traits.visibility">
...
...
@@ -256,7 +269,7 @@ class Aliased_Talker {
256
269
</para>
257
270
<example xml:id="language.oop5.traits.visibility.ex1">
258
271
<title>Changing Method Visibility</title>
259
-
<programlisting role="php">
272
+
<programlisting role="php" annotations="non-interactive">
260
273
<![CDATA[
261
274
<?php
262
275
trait HelloWorld {
...
...
@@ -332,12 +345,14 @@ Hello World!
332
345
<title>Abstract Trait Members</title>
333
346
<para>
334
347
Traits support the use of abstract methods in order to impose requirements
335
-
upon the exhibiting class.
348
+
upon the exhibiting class. Public, protected, and private methods are supported.
349
+
Prior to PHP 8.0.0, only public and protected abstract methods were supported.
336
350
</para>
337
351
<caution>
338
352
<simpara>
339
-
A concrete class fulfills this requirement by defining a concrete method
340
-
with the same name; its signature may be different.
353
+
As of PHP 8.0.0, the signature of a concrete method must follow the
354
+
<link linkend="language.oop.lsp">signature compatibility rules</link>.
355
+
Previously, its signature might be different.
341
356
</simpara>
342
357
</caution>
343
358
<example xml:id="language.oop5.traits.abstract.ex1">
...
...
@@ -371,54 +386,136 @@ class MyHelloWorld {
371
386
<sect2 xml:id="language.oop5.traits.static">
372
387
<title>Static Trait Members</title>
373
388
<para>
374
-
Traits can define both static members and static methods.
389
+
Traits can define static variables, static methods and static properties.
375
390
</para>
391
+
<note>
392
+
<para>
393
+
As of PHP 8.1.0, calling a static method, or accessing a static property directly on a trait is deprecated.
394
+
Static methods and properties should only be accessed on a class using the trait.
395
+
</para>
396
+
</note>
376
397
<example xml:id="language.oop5.traits.static.ex1">
377
398
<title>Static Variables</title>
378
399
<programlisting role="php">
379
400
<![CDATA[
380
401
<?php
381
-
trait Counter {
382
-
public function inc() {
402
+

403
+
trait Counter
404
+
{
405
+
public function inc()
406
+
{
383
407
static $c = 0;
384
408
$c = $c + 1;
385
409
echo "$c\n";
386
410
}
387
411
}
388
412

389
-
class C1 {
413
+
class C1
414
+
{
390
415
use Counter;
391
416
}
392
417

393
-
class C2 {
418
+
class C2
419
+
{
394
420
use Counter;
395
421
}
396
422

397
-
$o = new C1(); $o->inc(); // echo 1
398
-
$p = new C2(); $p->inc(); // echo 1
423
+
$o = new C1();
424
+
$o->inc();
425
+
$p = new C2();
426
+
$p->inc();
427
+

399
428
?>
400
429
]]>
401
430
</programlisting>
431
+
&example.outputs;
432
+
<screen>
433
+
<![CDATA[
434
+
1
435
+
1
436
+
]]>
437
+
</screen>
402
438
</example>
403
439
<example xml:id="language.oop5.traits.static.ex2">
404
440
<title>Static Methods</title>
405
441
<programlisting role="php">
406
442
<![CDATA[
407
443
<?php
408
-
trait StaticExample {
409
-
public static function doSomething() {
444
+

445
+
trait StaticExample
446
+
{
447
+
public static function doSomething()
448
+
{
410
449
return 'Doing something';
411
450
}
412
451
}
413
452

414
-
class Example {
453
+
class Example
454
+
{
415
455
use StaticExample;
416
456
}
417
457

418
-
Example::doSomething();
458
+
echo Example::doSomething();
459
+

460
+
?>
461
+
]]>
462
+
</programlisting>
463
+
&example.outputs;
464
+
<screen>
465
+
<![CDATA[
466
+
Doing something
467
+
]]>
468
+
</screen>
469
+
</example>
470
+
<example xml:id="language.oop5.traits.static.ex3">
471
+
<title>Static Properties</title>
472
+
<caution>
473
+
<simpara>
474
+
Prior to PHP 8.3.0, static properties defined in a trait were shared
475
+
across all classes in the same inheritance hierarchy which used that trait.
476
+
As of PHP 8.3.0, if a child class uses a trait with a static property,
477
+
it will be considered distinct from the one defined in the parent class.
478
+
</simpara>
479
+
</caution>
480
+
<programlisting role="php">
481
+
<![CDATA[
482
+
<?php
483
+

484
+
trait T
485
+
{
486
+
public static $counter = 1;
487
+
}
488
+

489
+
class A
490
+
{
491
+
use T;
492
+

493
+
public static function incrementCounter()
494
+
{
495
+
static::$counter++;
496
+
}
497
+
}
498
+

499
+
class B extends A
500
+
{
501
+
use T;
502
+
}
503
+

504
+
A::incrementCounter();
505
+

506
+
echo A::$counter, "\n";
507
+
echo B::$counter, "\n";
508
+

419
509
?>
420
510
]]>
421
511
</programlisting>
512
+
&example.outputs.83;
513
+
<screen>
514
+
<![CDATA[
515
+
2
516
+
1
517
+
]]>
518
+
</screen>
422
519
</example>
423
520
</sect2>
424
521

...
...
@@ -432,26 +529,28 @@ Example::doSomething();
432
529
<programlisting role="php">
433
530
<![CDATA[
434
531
<?php
435
-
trait PropertiesTrait {
532
+

533
+
trait PropertiesTrait
534
+
{
436
535
public $x = 1;
437
536
}
438
537

439
-
class PropertiesExample {
538
+
class PropertiesExample
539
+
{
440
540
use PropertiesTrait;
441
541
}
442
542

443
-
$example = new PropertiesExample;
543
+
$example = new PropertiesExample();
444
544
$example->x;
545
+

445
546
?>
446
547
]]>
447
548
</programlisting>
448
549
</example>
449
550
<para>
450
551
If a trait defines a property then a class can not define a property with
451
-
the same name unless it is compatible (same visibility and initial value),
452
-
otherwise a fatal error is issued.
453
-
Before PHP 7.0.0, defining a property in the class with the same visibility
454
-
and initial value as in the trait, raised an E_STRICT notice.
552
+
the same name unless it is compatible (same visibility and type,
553
+
readonly modifier, and initial value), otherwise a fatal error is issued.
455
554
</para>
456
555
<example xml:id="language.oop5.traits.properties.conflicts">
457
556
<title>Conflict Resolution</title>
...
...
@@ -460,13 +559,17 @@ $example->x;
460
559
<?php
461
560
trait PropertiesTrait {
462
561
public $same = true;
463
-
public $different = false;
562
+
public $different1 = false;
563
+
public bool $different2;
564
+
public bool $different3;
464
565
}
465
566

466
567
class PropertiesExample {
467
568
use PropertiesTrait;
468
-
public $same = true; // Allowed as of PHP 7.0.0; E_STRICT notice formerly
469
-
public $different = true; // Fatal error
569
+
public $same = true;
570
+
public $different1 = true; // Fatal error
571
+
public string $different2; // Fatal error
572
+
readonly protected bool $different3; // Fatal error
470
573
}
471
574
?>
472
575
]]>
...
...
@@ -474,8 +577,110 @@ class PropertiesExample {
474
577
</example>
475
578
</sect2>
476
579

477
-
</sect1>
580
+
<sect2 xml:id="language.oop5.traits.constants">
581
+
<title>&Constants;</title>
582
+
<para>
583
+
Traits can, as of PHP 8.2.0, also define constants.
584
+
</para>
585
+
<example xml:id="language.oop5.traits.constants.example">
586
+
<title>Defining Constants</title>
587
+
<programlisting role="php">
588
+
<![CDATA[
589
+
<?php
590
+
trait ConstantsTrait {
591
+
public const FLAG_MUTABLE = 1;
592
+
final public const FLAG_IMMUTABLE = 5;
593
+
}
478
594

595
+
class ConstantsExample {
596
+
use ConstantsTrait;
597
+
}
598
+

599
+
$example = new ConstantsExample;
600
+
echo $example::FLAG_MUTABLE;
601
+
?>
602
+
]]>
603
+
</programlisting>
604
+
&example.outputs;
605
+
<screen>
606
+
<![CDATA[
607
+
1
608
+
]]>
609
+
</screen>
610
+
</example>
611
+
<para>
612
+
If a trait defines a constant then a class can not define a constant with
613
+
the same name unless it is compatible (same visibility, initial value, and
614
+
finality), otherwise a fatal error is issued.
615
+
</para>
616
+
<example xml:id="language.oop5.traits.constants.conflicts">
617
+
<title>Conflict Resolution</title>
618
+
<programlisting role="php">
619
+
<![CDATA[
620
+
<?php
621
+
trait ConstantsTrait {
622
+
public const FLAG_MUTABLE = 1;
623
+
final public const FLAG_IMMUTABLE = 5;
624
+
}
625
+

626
+
class ConstantsExample {
627
+
use ConstantsTrait;
628
+
public const FLAG_IMMUTABLE = 5; // Fatal error
629
+
}
630
+
?>
631
+
]]>
632
+
</programlisting>
633
+
</example>
634
+
</sect2>
635
+

636
+
<sect2 xml:id="language.oop5.traits.final-methods">
637
+
<title>Final methods</title>
638
+
<simpara>
639
+
As of PHP 8.3.0, the <link linkend="language.oop5.final">final</link>
640
+
modifier can be applied using the <literal>as</literal> operator
641
+
to methods imported from traits. This can be used to prevent child classes
642
+
from overriding the method. However, the class that uses the trait can still
643
+
override the method.
644
+
</simpara>
645
+
<example xml:id="language.oop5.traits.final-methods.example">
646
+
<title>Defining a method coming from a trait as <literal>final</literal></title>
647
+
<programlisting role="php">
648
+
<![CDATA[
649
+
<?php
650
+

651
+
trait CommonTrait
652
+
{
653
+
public function method()
654
+
{
655
+
echo 'Hello';
656
+
}
657
+
}
658
+

659
+
class FinalExampleA
660
+
{
661
+
use CommonTrait {
662
+
CommonTrait::method as final; // The 'final' prevents child classes from overriding the method
663
+
}
664
+
}
665
+

666
+
class FinalExampleB extends FinalExampleA
667
+
{
668
+
public function method() {}
669
+
}
670
+

671
+
?>
672
+
]]>
673
+
</programlisting>
674
+
&example.outputs.similar;
675
+
<screen>
676
+
<![CDATA[
677
+
Fatal error: Cannot override final method FinalExampleA::method() in ...
678
+
]]>
679
+
</screen>
680
+
</example>
681
+
</sect2>
682
+

683
+
</sect1>
479
684
<!-- Keep this comment at the end of the file
480
685
Local variables:
481
686
mode: sgml
482
687