-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathtraits.xml
719 lines (655 loc) · 16.3 KB
/
traits.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: c1f37a6c270aadbbb3da56a3973ffd62197adf2b Maintainer: simp Status: ready -->
<!-- Reviewed: no -->
<sect1 xml:id="language.oop5.traits" xmlns="http://docbook.org/ns/docbook">
<title>Traits</title>
<para>
In PHP gibt es eine Methode der Wiederverwendung von Code, die Traits
genannt wird.
</para>
<para>
Traits sind ein Mechanismus zur Wiederverwendung von Code, der in
Programmiersprachen mit einfacher Vererbung wie PHP verwendet wird. Ein
Trait kann verwendet werden, um den Beschränkungen der einfachen Vererbung
auszuweichen, indem er erlaubt, dass Mengen von Methoden frei in
mehreren unabhängigen Klassen, die in verschiedenen Klassenhierarchien
stecken, wiederzuverwenden. Die Semantik der Kombination von Traits und
Klassen ist so definiert, dass die Komplexität reduziert wird und die
üblichen Probleme vermeidet, die mit Mehrfachvererbung und Mixins in
Verbindung gebracht werden.
</para>
<para>
Ein Trait hat Ähnlichkeit mit einer Klasse, ist aber nur dafür vorgesehen,
Funktionalität in einer feingranularen und konsistenten Art und Weise zu
bündeln. Es ist nicht möglich einen Trait alleinstehend zu instantiieren.
Es handelt sich um einen Zusatz zur traditionellen Vererbung und erlaubt
horizontale Komposition von Verhaltensweisen, &dh; die Verwendung von
Klassenmethoden ohne Vererbung vorauszusetzen.
</para>
<example xml:id="language.oop5.traits.basicexample">
<title>Trait-Beispiel</title>
<programlisting role="php">
<![CDATA[
<?php
trait TraitA {
public function sayHello() {
echo 'Hello';
}
}
trait TraitB {
public function sayWorld() {
echo 'World';
}
}
class MyHelloWorld
{
use TraitA, TraitB; // Eine Klasse kann mehrere Traits verwenden
public function sayHelloWorld() {
$this->sayHello();
echo ' ';
$this->sayWorld();
echo "!\n";
}
}
$myHelloWorld = new MyHelloWorld();
$myHelloWorld->sayHelloWorld();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Hello World!
]]>
</screen>
</example>
<sect2 xml:id="language.oop5.traits.precedence">
<title>Rangfolge</title>
<para>
Methoden der aktuellen Klasse überschreiben Methoden, welche von Traits
definiert wurden. Jene wiederum überschreiben von Elternklassen geerbte
Methoden.
</para>
<example xml:id="language.oop5.traits.precedence.examples.ex1">
<title>Rangfolge-Beispiel</title>
<para>
Die Methode <literal>sayHello</literal> der Basisklasse wird durch die
gleichnamige Methode aus dem Trait überschrieben.
</para>
<programlisting role="php">
<![CDATA[
<?php
class Base {
public function sayHello() {
echo 'Hallo ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'Welt!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Hallo Welt!
]]>
</screen>
</example>
<example xml:id="language.oop5.traits.precedence.examples.ex2">
<title>Weiteres Beispiel für Rangfolge</title>
<programlisting role="php">
<![CDATA[
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hallo Welt!';
}
}
class TheWorldIsNotEnough {
use HelloWorld;
public function sayHello() {
echo 'Hallo Universum!';
}
}
$o = new TheWorldIsNotEnough();
$o->sayHello();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Hallo Universum!
]]>
</screen>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.multiple">
<title>Mehrere Traits</title>
<para>
Mehrere Traits können durch eine kommaseparierte Auflistung im
<literal>use</literal>-Statement zu einer Klasse hinzugefügt werden.
</para>
<example xml:id="language.oop5.traits.multiple.ex1">
<title>Verwendung mehrerer Traits</title>
<programlisting role="php">
<![CDATA[
<?php
trait Hello {
public function sayHello() {
echo 'Hallo ';
}
}
trait World {
public function sayWorld() {
echo ' Welt';
}
}
class MyHelloWorld {
use Hello, World;
public function sayExclamationMark() {
echo '!';
}
}
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Hallo Welt!
]]>
</screen>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.conflict">
<title>Konfliktauflösung</title>
<para>
Falls zwei Traits eine Methode mit gleichem Namen einfügen, so wird ein
Fatal Error erzeugt, wenn der Konflikt nicht explizit aufgelöst wird.
</para>
<para>
Um einen Namenskonflikt zwischen Traits in der gleichen Klasse aufzulösen
muss der <literal>insteadof</literal>-Operator verwendet werden, um
genau eine der Methoden des Konflikts auszuwählen.
</para>
<para>
Da dies es nur erlaubt Methoden auszuschließen kann der
<literal>as</literal>-Operator verwendet werden, um einen Alias zu einer der
Methoden hinzuzufügen. Es ist zu beachten, dass der <literal>as</literal>
Operator die Methode nicht umbenennt, und auch keine andere Methode
beeinflusst.
</para>
<example xml:id="language.oop5.traits.conflict.ex1">
<title>Konfliktauflösung</title>
<para>
In diesem Beispiel verwendet die Klasse Talker die Traits A und B.
Nachdem A und B sich widersprechende Methoden besitzen definiert die
Klasse, dass sie die Variante von smallTalk aus dem Trait B und die
Variante von bigTalk des Traits A verwenden möchte.
</para>
<para>
Die Klasse Aliased_Talker verwendet den <literal>as</literal>-Operator,
damit sie außerdem die Implementierung der bigTalk-Methode von B unter dem
Alias <literal>talk</literal> verwenden kann.
</para>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
trait A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
}
trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
}
class Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}
class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
?>
]]>
</programlisting>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.visibility">
<title>Veränderung der Sichtbarkeit von Methoden</title>
<para>
Mit der <literal>as</literal>-Syntax ist es ebenso möglich, die
Sichtbarkeit einer Methode in der darstellenden Klasse zu verändern.
</para>
<example xml:id="language.oop5.traits.visibility.ex1">
<title>Veränderung der Sichtbarkeit von Methoden</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hallo Welt!';
}
}
// Ändern der Sichtbarkeit von sayHello
class MyClass1 {
use HelloWorld { sayHello as protected; }
}
// Alias der Methode mit geänderter Sichtbarkeit
// Die Sichtbarkeit von sayHello bleibt unverändert
class MyClass2 {
use HelloWorld { sayHello as private myPrivateHello; }
}
?>
]]>
</programlisting>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.composition">
<title>Trait-Zusammensetzung aus Traits</title>
<para>
Ebenso wie Klassen können auch Traits andere Traits verwenden. Indem
man einen oder mehrere Traits in einer Traitdefinition verwendet kann man
Traits entweder teilweise oder vollständig aus Methoden, welche in anderen
Traits definiert sind, zusammensetzen.
</para>
<example xml:id="language.oop5.traits.composition.ex1">
<title>Trait-Zusammensetzung aus Traits</title>
<programlisting role="php">
<![CDATA[
<?php
trait Hello {
public function sayHello() {
echo 'Hallo ';
}
}
trait World {
public function sayWorld() {
echo 'Welt!';
}
}
trait HelloWorld {
use Hello, World;
}
class MyHelloWorld {
use HelloWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Hallo Welt!
]]>
</screen>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.abstract">
<title>Abstrakte Traitmember</title>
<para>
Traits unterstützen auch die Verwendung von abstrakten Methoden, um
darstellenden Klassen Anforderungen vorzugeben. Es werden öffentliche,
geschützte und private Methoden unterstützt. Vor PHP 8.0.0 wurden nur
öffentliche und geschützte abstrakte Methoden unterstützt.
</para>
<caution>
<simpara>
Seit PHP 8.0.0 muss die Signatur einer konkreten Methode den
<link linkend="language.oop.lsp">Regeln zur Signaturkompatibilität</link>
entsprechen; zuvor durfte ihre Signatur davon abweichen.
</simpara>
</caution>
<example xml:id="language.oop5.traits.abstract.ex1">
<title>Ausdrücken von Anforderungen durch abstrakte Methoden</title>
<programlisting role="php">
<![CDATA[
<?php
trait Hello {
public function sayHelloWorld() {
echo 'Hallo'.$this->getWorld();
}
abstract public function getWorld();
}
class MyHelloWorld {
private $world;
use Hello;
public function getWorld() {
return $this->world;
}
public function setWorld($val) {
$this->world = $val;
}
}
?>
]]>
</programlisting>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.static">
<title>Statische Traitmember</title>
<para>
Traits unterstützen sowohl statische Variablen, statische Methoden und
statische Eignschaften.
</para>
<note>
<para>
Seit PHP 8.1.0 sind der Aufruf einer statischen Methode oder der Zugriff
auf eine statische Eigenschaft direkt in einem Trait veraltet. Auf
statische Methoden und Eigenschaften sollte nur in einer Klasse
zugegriffen werden, die den Trait verwendet.
</para>
</note>
<example xml:id="language.oop5.traits.static.ex1">
<title>Statische Variablen</title>
<programlisting role="php">
<![CDATA[
<?php
trait Counter
{
public function inc()
{
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
}
class C1
{
use Counter;
}
class C2
{
use Counter;
}
$o = new C1();
$o->inc();
$p = new C2();
$p->inc();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
1
1
]]>
</screen>
</example>
<example xml:id="language.oop5.traits.static.ex2">
<title>Statische Methoden</title>
<programlisting role="php">
<![CDATA[
<?php
trait StaticExample
{
public static function doSomething()
{
return 'Tue etwas';
}
}
class Example
{
use StaticExample;
}
echo Example::doSomething();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Doing something
]]>
</screen>
</example>
<example xml:id="language.oop5.traits.static.ex3">
<title>Statische Eigenschaften</title>
<caution>
<simpara>
Vor PHP 8.3.0 wurden statische Eigenschaften, die in einem Trait
definiert waren, von allen Klassen in derselben Vererbungshierarchie, die
diesen Trait verwendeten, gemeinsam genutzt.
Seit PHP 8.3.0 wird eine statische Eigenschaft, die von einer Kindklasse
über einen Trait verwendet wird, als von der in der Elternklasse
definierte Eigenschaft unterschieden betrachtet.
</simpara>
</caution>
<programlisting role="php">
<![CDATA[
<?php
trait T
{
public static $counter = 1;
}
class A
{
use T;
public static function incrementCounter()
{
static::$counter++;
}
}
class B extends A
{
use T;
}
A::incrementCounter();
echo A::$counter, "\n";
echo B::$counter, "\n";
?>
]]>
</programlisting>
&example.outputs.83;
<screen>
<![CDATA[
2
1
]]>
</screen>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.properties">
<title>Eigenschaften</title>
<para>
Traits können ebenfalls Eigenschaften definieren.
</para>
<example xml:id="language.oop5.traits.properties.example">
<title>Eigenschaften definieren</title>
<programlisting role="php">
<![CDATA[
<?php
trait PropertiesTrait
{
public $x = 1;
}
class PropertiesExample
{
use PropertiesTrait;
}
$example = new PropertiesExample();
$example->x;
?>
]]>
</programlisting>
</example>
<para>
Definiert ein Trait eine Eigenschaft, dann kann eine Klasse keine Eigenschaft
mit dem selben Namen definieren, es sei denn, sie ist kompatibel (selbe
Sichtbarkeit und Typ, readonly-Modifikator und Initialwert); andernfalls wird
ein fataler Fehler auftreten.
</para>
<example xml:id="language.oop5.traits.properties.conflicts">
<title>Konfliktauflösung</title>
<programlisting role="php">
<![CDATA[
<?php
trait PropertiesTrait {
public $same = true;
public $different1 = false;
public bool $different2;
public bool $different3;
}
class PropertiesExample {
use PropertiesTrait;
public $same = true;
public $different1 = true; // Fatal error
public string $different2; // Fatal error
readonly protected bool $different3; // Fatal error
}
?>
]]>
</programlisting>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.constants">
<title>&Constants;</title>
<para>
Seit PHP 8.2.0 können Traits auch Konstanten definieren.
</para>
<example xml:id="language.oop5.traits.constants.example">
<title>Definieren von Konstanten</title>
<programlisting role="php">
<![CDATA[
<?php
trait ConstantsTrait {
public const FLAG_MUTABLE = 1;
final public const FLAG_IMMUTABLE = 5;
}
class ConstantsExample {
use ConstantsTrait;
}
$example = new ConstantsExample;
echo $example::FLAG_MUTABLE;
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
1
]]>
</screen>
</example>
<para>
Wenn ein Trait eine Konstante definiert, kann eine Klasse keine Konstante
mit demselben Namen definieren, es sei denn, sie ist kompatibel (dieselbe
Sichtbarkeit, derselbe Initialwert und dieselbe Finalität), andernfalls
wird ein fataler Fehler ausgegeben.
</para>
<example xml:id="language.oop5.traits.constants.conflicts">
<title>Konfliktauflösung</title>
<programlisting role="php">
<![CDATA[
<?php
trait ConstantsTrait {
public const FLAG_MUTABLE = 1;
final public const FLAG_IMMUTABLE = 5;
}
class ConstantsExample {
use ConstantsTrait;
public const FLAG_IMMUTABLE = 5; // Fatal error
}
?>
]]>
</programlisting>
</example>
</sect2>
<sect2 xml:id="language.oop5.traits.final-methods">
<title>Finale Methoden</title>
<simpara>
Seit PHP 8.3.0 kann der Modifikator
<link linkend="language.oop5.final">final</link> mit dem Operator
<literal>as</literal> auf Methoden angewendet werden, die aus Traits
importiert wurden. Dies kann verwendet werden, um zu verhindern, dass
Kindklassen die Methode überschreiben. Die Klasse, die den Trait verwendet,
kann die Methode jedoch weiterhin überschreiben.
</simpara>
<example xml:id="language.oop5.traits.final-methods.example">
<title>Definieren einer Methode aus einem Trait als <literal>final</literal></title>
<programlisting role="php">
<![CDATA[
<?php
trait CommonTrait
{
public function method()
{
echo 'Hello';
}
}
class FinalExampleA
{
use CommonTrait {
CommonTrait::method as final; // Das "final" verhindert, dass Kindklassen
// die Methode überschreiben.
}
}
class FinalExampleB extends FinalExampleA
{
public function method() {}
}
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
Fatal error: Cannot override final method FinalExampleA::method() in ...
]]>
</screen>
</example>
</sect2>
</sect1>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->