-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathdecon.xml
446 lines (418 loc) · 15.7 KB
/
decon.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
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: c1f37a6c270aadbbb3da56a3973ffd62197adf2b Maintainer: hholzgra Status: ready -->
<!-- Reviewed: yes -->
<!-- Rev-Revision: 9ee9eccf455188ab6eb352194eb6f9eb99e15606 Reviewer: samesch -->
<!-- Credits: simp -->
<sect1 xml:id="language.oop5.decon" xmlns="http://docbook.org/ns/docbook">
<title>Konstruktoren und Destruktoren</title>
<sect2 xml:id="language.oop5.decon.constructor">
<title>Konstruktor</title>
<methodsynopsis xml:id="object.construct">
<type>void</type><methodname>__construct</methodname>
<methodparam rep="repeat"><type>mixed</type><parameter>values</parameter><initializer>""</initializer></methodparam>
</methodsynopsis>
<para>
PHP erlaubt es Entwicklern, Konstruktormethoden für Klassen zu deklarieren.
Klassen mit Konstruktormethoden rufen diese für jedes neu erzeugte Objekt
auf, sodass Konstruktoren für alle Initialisierungen passend sind, die das
Objekt brauchen könnte, bevor es benutzt wird.
</para>
<note>
<simpara>
Konstruktoren von Elternklassen werden nicht implizit aufgerufen, wenn
die Kindklasse einen Konstruktor definiert. Um einen Elternkonstruktor zu
benutzen, ist ein Aufruf von <function>parent::__construct</function>
innerhalb des Kindkonstruktors notwendig. Falls das Kind keinen
Konstruktor definiert, kann er von der Elternklasse genau wie eine
normale Klassenmethode geerbt werden (falls er nicht als privat
deklariert wurde).
</simpara>
</note>
<example>
<title>Konstruktoren bei der Vererbung</title>
<programlisting role="php">
<![CDATA[
<?php
class BaseClass {
function __construct() {
print "Im BaseClass-Konstruktor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "Im SubClass-Konstruktor\n";
}
}
class OtherSubClass extends BaseClass {
// erbt den Konstruktor von BaseClass
}
// Im BaseClass-Konstruktor
$obj = new BaseClass();
// Im BaseClass-Konstruktor
// Im SubClass-Konstruktor
$obj = new SubClass();
// Im BaseClass-Konstruktor
$obj = new OtherSubClass();
?>
]]>
</programlisting>
</example>
<para>
Im Gegensatz zu anderen Methoden ist
<link linkend="object.construct">__construct()</link> ist ausgenommen von
den üblichen
<link linkend="language.oop.lsp">Regeln für die Signaturkompatibilität</link>.
wenn sie erweitert wird.
</para>
<para>
Konstruktoren sind gewöhnliche Methoden, die bei der Instanziierung des
entsprechenden Objekts aufgerufen werden. Als solche können sie eine
beliebige Anzahl von Argumenten definieren, die erforderlich sein können,
einen Typ haben können und einen Standardwert haben können.
Konstruktorargumente werden aufgerufen, indem die Argumente in Klammern
hinter den Klassennamen gesetzt werden.
</para>
<example>
<title>Die Verwendung von Argumenten eines Konstruktors</title>
<programlisting role="php">
<![CDATA[
<?php
class Punkt {
protected int $x;
protected int $y;
public function __construct(int $x, int $y = 0) {
$this->x = $x;
$this->y = $y;
}
}
// Beide Parameter übergeben.
$p1 = new Punkt(4, 5);
// Nur den erforderlichen Parameter übergeben. $y nimmt den Standardwert von 0 an.
$p2 = new Punkt(4);
// Mit benannten Parametern (von PHP 8.0 an):
$p3 = new Punkt(y: 5, x: 4);
?>
]]>
</programlisting>
</example>
<para>
Wenn eine Klasse keinen Konstruktor hat oder der Konstruktor keine
erforderlichen Argumente hat, können die Klammern weggelassen werden.
</para>
<sect3>
<title>Konstruktoren alten Stils</title>
<para>
Vor PHP 8.0.0 interpretieren Klassen im globalen Namensraum eine Methode,
die den gleichen Namen wie die Klasse trägt, als Konstruktor alten Stils.
Diese Syntax ist veraltet, und führt zu einem
<constant>E_DEPRECATED</constant>-Fehler, ruft die Funktion aber trotzdem
als Konstruktor auf. Wenn sowohl
<link linkend="object.construct">__construct()</link> als auch eine
Methode gleichen Namens definiert sind, wird
<link linkend="object.construct">__construct()</link> aufgerufen.
</para>
<para>
In Namensraum-Klassen, oder ab PHP 8.0.0 in jeder Klasse, hat eine
Methode mit dem Namen der Klasse keine besondere Bedeutung.
</para>
<para>
Verwenden Sie in neuem Code immer
<link linkend="object.construct">__construct()</link>.
</para>
</sect3>
<sect3 xml:id="language.oop5.decon.constructor.promotion">
<title>Promotion (Beförderung) des Konstruktors</title>
<para>
Ab PHP 8.0.0 können Konstruktorparameter auch so befördert werden, dass
sie einer Objekteigenschaft entsprechen. Sehr häufig werden
Konstruktorparameter einer Eigenschaft im Konstruktor zugewiesen, aber
ansonsten nicht bearbeitet. Die Konstruktor-Promotion bietet eine
Kurzform für diesen Anwendungsfall. Das obige Beispiel könnte wie folgt
umgeschrieben werden:
</para>
<example>
<title>Die Verwendung der Beförderung von Konstruktor-Eigenschaften</title>
<programlisting role="php">
<![CDATA[
<?php
class Punkt {
public function __construct(protected int $x, protected int $y = 0) {
}
}
]]>
</programlisting>
</example>
<para>
Wenn ein Konstruktorargument einen Modifizierer enthält,
interpretiert PHP es sowohl als Objekteigenschaft als auch als
Konstruktorargument und weist der Eigenschaft den Wert des Arguments zu.
Der Konstruktorkörper kann dann leer sein oder andere Anweisungen
enthalten. Alle zusätzlichen Anweisungen werden ausgeführt, nachdem die
Argumentwerte den entsprechenden Eigenschaften zugewiesen wurden.
</para>
<para>
Nicht alle Argumente müssen befördert werden. Beförderte und nicht
beförderte Argumente können in beliebiger Reihenfolge zu kombiniert
werden. Beförderte Argumente haben keinen Einfluss auf den Code, der den
Konstruktor aufruft.
</para>
<note>
<para>
Eigenschaften werden wahrscheinlich meist mit einem
<link linkend="language.oop5.visibility">Sichtbarkeitsmodifikator</link>
(<literal>public</literal>, <literal>protected</literal> oder
<literal>private</literal>) befördert, aber jeder andere einzelne
Modifikator (&zb; <literal>readonly</literal>) hat denselben Effekt.
</para>
</note>
<note>
<para>
Objekteigenschaften dürfen aufgrund der Mehrdeutigkeit, die in die
Engine einfließen würde, nicht mit <type>callable</type> typisiert
werden. Somit dürfen die angeführten Argumente auch nicht mit
<type>callable</type> typisiert werden. Jede andere
<link linkend="language.types.declarations">Typ-Deklaration</link> ist
jedoch erlaubt.
</para>
</note>
<note>
<para>
Da beförderte Eigenschaften sowohl zu einer Eigenschaft als auch zu
einem Funktionsparameter gemacht werden, gelten alle
Namensbeschränkungen sowohl für Eigenschaften als auch für Parameter.
</para>
</note>
<note>
<para>
<link linkend="language.attributes">Attribute</link>, die auf ein
befördertes Konstruktorargument gelegt werden, werden sowohl auf die
Eigenschaft als auch auf das Argument übertragen. Die Standardwerte für
ein befördertes Konstruktorargument werden nur auf das Argument und
nicht auf die Eigenschaft übertragen.
</para>
</note>
</sect3>
<sect3 xml:id="language.oop5.decon.constructor.new">
<title>New bei der Initialisierung</title>
<para>
Ab PHP 8.1.0 können Objekte als Standardwerte für Parameter, als
statische Variablen und globale Konstanten sowie in
Eigenschaftsparametern verwendet werden. Objekte können nun auch an
<function>define</function> übergeben werden.
</para>
<note>
<para>
Es ist nicht zulässig, einen dynamischen Klassennamen, einen
Klassennamen, der keine Zeichenkette ist, oder eine anonyme Klasse zu
verwenden. Es ist auch nicht zulässig, Parameter zu entpacken, und nicht
unterstützte Ausdrücke als Parameter zu verwenden.
</para>
</note>
<example>
<title>Verwendung von new bei Initialisierungen</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
// Alles zulässig:
static $x = new Foo;
const C = new Foo;
function test($param = new Foo) {}
#[AnAttribute(new Foo)]
class Test {
public function __construct(
public $prop = new Foo,
) {}
}
// Alles nicht zulässig (Kompilierfehler):
function test(
$a = new (CLASS_NAME_CONSTANT)(), // dynamischer Klassenname
$b = new class {}, // anonyme Klasse
$c = new A(...[]), // Entpacken von Parametern
$d = new B($abc), // nicht unterstützter Ausdruck
) {}
?>
]]>
</programlisting>
</example>
</sect3>
<sect3 xml:id="language.oop5.decon.constructor.static">
<title>Erzeugung über statische Methoden</title>
<para>
PHP unterstützt nur einen einzigen Konstruktor pro Klasse. In einigen
Fällen, kann es jedoch wünschenswert sein, dass ein Objekt auf
verschiedene Weisen mit unterschiedlichen Eingaben erzeugt werden kann.
Der empfohlene Weg, dies zu tun, ist die, Konstruktoren in statische
Methoden zu packen.
</para>
<example>
<title>Die Erzeugung über statische Methoden verwenden</title>
<programlisting role="php">
<![CDATA[
<?php
$some_json_string = '{ "id": 1004, "name": "Elephpant" }';
$some_xml_string = "<animal><id>1005</id><name>Elephpant</name></animal>";
class Produkt {
private ?int $id;
private ?string $name;
private function __construct(?int $id = null, ?string $name = null) {
$this->id = $id;
$this->name = $name;
}
public static function fromBasicData(int $id, string $name): static {
$neu = new static($id, $name);
return $neu;
}
public static function fromJson(string $json): static {
$daten = json_decode($json, true);
return new static($daten['id'], $daten['name']);
}
public static function fromXml(string $xml): static {a
$data = simplexml_load_string($xml);
$neu = new static();
$neu->id = $daten->id;
$neu->name = $daten->name;
return $neu;
}
}
$p1 = Produkt::fromBasicData(5, 'Widget');
$p2 = Produkt::fromJson($some_json_string);
$p3 = Produkt::fromXml($some_xml_string);
var_dump($p1, $p2, $p3);
]]>
</programlisting>
</example>
<para>
Der Konstruktor kann private oder protected gemacht werden, um zu
verhindern, dass er von außen aufgerufen wird. Wenn dies der Fall ist,
kann nur eine statische Methode die Klasse instanziieren. Da sie in der
gleichen Klassendefinition enthalten ist, hat sie Zugriff auf private
Methoden, auch wenn sie nicht zur gleichen Objektinstanz gehören. Der
private Konstruktor ist optional und kann je nach Anwendungsfall sinnvoll
sein oder nicht.
</para>
<para>
Die drei public static Methoden veranschaulichen dann verschiedene
Möglichkeiten das Objekt zu instanziieren.
</para>
<simplelist>
<member><code>fromBasicData()</code> nimmt genau die Parameter, die
benötigt werden, erzeugt dann das Objekt durch Aufruf des Konstruktors
und Rückgabe des Ergebnisses.</member>
<member><code>fromJson()</code> akzeptiert eine JSON-Zeichenkette und
führt selbst eine Vorverarbeitung durch, um sie in das vom Konstruktor
gewünschte Format zu konvertieren. Sie gibt dann das neue Objekt
zurück.</member>
<member><code>fromXml()</code> akzeptiert eine XML-Zeichenkette,
vorverarbeitet sie und erzeugt dann ein leeres Objekt. Der Konstruktor
wird immer noch aufgerufen, aber da alle Parameter optional sind,
überspringt sie die Methode. Sie weist dann den Objekteigenschaften
direkt Werte zu, bevor sie das Ergebnis zurückgibt.</member>
</simplelist>
<para>
In allen drei Fällen wird das Schlüsselwort <code>static</code> in den
Namen der Klasse übersetzt, in der sich der Code befindet. In diesem
Fall: <code>Produkt</code>.
</para>
</sect3>
</sect2>
<sect2 xml:id="language.oop5.decon.destructor">
<title>Destruktor</title>
<methodsynopsis xml:id="object.destruct">
<type>void</type><methodname>__destruct</methodname>
<void />
</methodsynopsis>
<para>
PHP verfügt über ein Destruktorkonzept ähnlich dem anderer
objektorientierter Programmiersprachen wie C++. Die Destruktormethode wird
aufgerufen, sobald es keine weiteren Referenzen auf ein bestimmtes Objekt
mehr gibt, oder in beliebiger Reihenfolge am Ende des Skripts.
</para>
<example>
<title>Destruktor-Beispiel</title>
<programlisting role="php">
<![CDATA[
<?php
class MyDestructableClass
{
function __construct() {
print "Im Konstruktor\n";
}
function __destruct() {
print "Zerstoere " . __CLASS__ . "\n";
}
}
$obj = new MyDestructableClass();
]]>
</programlisting>
</example>
<para>
Wie Konstruktoren auch, werden Elterndestruktoren nicht implizit durch die
Engine aufgerufen. Um einen Elterndestruktor zu benutzen muss man explizit
die Funktion <function>parent::__destruct</function> in der
Destruktorimplementierung aufrufen. Ebenso wie Konstruktoren kann eine
Kindklasse den Destruktor der Eltern erben, falls sie keinen eigenen
implementiert.
</para>
<para>
Der Destruktor wird aufgerufen, wenn das Skript mittels
<function>exit</function> abgebrochen wird. Wenn <function>exit</function>
innerhalb eines Destruktors aufgerufen wird, verhindert das die Ausführung
von jeglichen weiteren Shutdown-Routinen.
</para>
<para>
Wenn ein Destruktor neue Referenzen auf sein Objekt erzeugt, wird er nicht
ein zweites Mal aufgerufen, wenn die Anzahl der Referenzen wieder Null
erreicht oder während der Abschaltsequenz.
</para>
<para>
Seit PHP 8.4.0 werden, wenn die
<link linkend="features.gc.collecting-cycles">Sammlung zyklischer Referenzen</link>
während der Ausführung einer <link linkend="language.fibers">Fiber</link>
stattfindet, die Destruktoren von Objekten, die für die Sammlung vorgesehen
sind, in einer separaten Fiber namens <literal>gc_destructor_fiber</literal>
ausgeführt.
Wenn diese Fiber unterbrochen wird, wird eine neue erstellt, um alle
verbleibenden Destruktoren auszuführen.
Die vorherige <literal>gc_destructor_fiber</literal> wird vom Garbage
Collector nicht mehr referenziert und kann, wenn sie nicht anderweitig
referenziert wird, eingesammelt werden.
Objekte, deren Destruktor ausgesetzt ist, werden nicht eingesammelt, bis
der Destruktor zurückgibt oder die Fiber selbst eingesammelt wird.
</para>
<note>
<para>
Der Destruktor wird während der Skript-Abschaltung aufgerufen, weshalb die
Header immer bereits gesendet sind. Das aktuelle Verzeichnis während der
Beendigungsphase des Skripts kann bei einigen SAPIs (&zb; Apache)
ein anderes sein.
</para>
</note>
<note>
<para>
Der Versuch, eine Exception aus einem Destruktor (der am Ende des Skripts
aufgerufen wird) heraus zu auszulösen, führt zu einem fatalen Fehler.
</para>
</note>
</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
-->