-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathattributes.xml
More file actions
409 lines (338 loc) · 11.2 KB
/
attributes.xml
File metadata and controls
409 lines (338 loc) · 11.2 KB
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
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 0f14761ba340c6e49797706ac3f0cf1147d97253 Maintainer: samesch Status: ready -->
<!-- Reviewed: no -->
<chapter xml:id="language.attributes" xmlns="http://docbook.org/ns/docbook">
<title>Attribute</title>
<sect1 xml:id="language.attributes.overview">
<title>Übersicht über die Attribute</title>
<?phpdoc print-version-for="attributes"?>
<para>
PHP-Attribute bieten strukturierte, maschinenlesbare Metadaten für Klassen,
Methoden, Funktionen, Parameter, Eigenschaften und Konstanten. Sie können
zur Laufzeit über die
<link linkend="book.reflection">Reflection-API</link> inspiziert werden und
ermöglichen dynamisches Verhalten ohne Änderung des Codes. Attribute bieten
eine deklarative Möglichkeit, den Code mit Metadaten zu kommentieren.
</para>
<para>
Attribute ermöglichen es, die Implementierung eines Merkmals von seiner
Verwendung zu trennen. Während Schnittstellen die Struktur definieren,
indem sie Methoden vorschreiben, liefern Attribute Metadaten über mehrere
Elemente, einschließlich Methoden, Funktionen, Eigenschaften und
Konstanten. Im Gegensatz zu Schnittstellen, die die Implementierung von
Methoden vorschreiben, kommentieren Attribute den Code, ohne dessen
Struktur zu verändern.
</para>
<para>
Attribute können optionale Schnittstellenmethoden ergänzen oder ersetzen,
indem sie Metadaten anstelle einer vorgeschriebenen Struktur bereitstellen.
Ein Beispiel könnte eine <literal>ActionHandler</literal>-Schnittstelle
sein, die eine Operation in einer Anwendung repräsentiert. Einige
Implementierungen könnten einen Konfigurationsschritt erfordern, während
andere dies nicht tun.
Anstatt alle Klassen, die <literal>ActionHandler</literal> implementieren,
zu zwingen, eine <literal>setUp()</literal>-Methode zu definieren, kann ein
Attribut die Setup-Anforderungen spezifizieren. Dieser Ansatz erhöht die
Flexibilität, da Attribute bei Bedarf mehrfach verwendet werden können.
</para>
<example>
<title>Implementierung optionaler Methoden einer Schnittstelle mit Hilfe von Attributen</title>
<programlisting role="php">
<![CDATA[
<?php
interface ActionHandler
{
public function execute();
}
#[Attribute]
class SetUp {}
class CopyFile implements ActionHandler
{
public string $fileName;
public string $targetDirectory;
#[SetUp]
public function fileExists()
{
if (!file_exists($this->fileName)) {
throw new RuntimeException("Die Datei existiert nicht");
}
}
#[SetUp]
public function targetDirectoryExists()
{
if (!file_exists($this->targetDirectory)) {
mkdir($this->targetDirectory);
} elseif (!is_dir($this->targetDirectory)) {
throw new RuntimeException("Das Zielverzeichnis $this->targetDirectory ist kein Verzeichnis");
}
}
public function execute()
{
copy($this->fileName, $this->targetDirectory . '/' . basename($this->fileName));
}
}
function executeAction(ActionHandler $actionHandler)
{
$reflection = new ReflectionObject($actionHandler);
foreach ($reflection->getMethods() as $method) {
$attributes = $method->getAttributes(SetUp::class);
if (count($attributes) > 0) {
$methodName = $method->getName();
$actionHandler->$methodName();
}
}
$actionHandler->execute();
}
$copyAction = new CopyFile();
$copyAction->fileName = "/tmp/foo.jpg";
$copyAction->targetDirectory = "/home/user";
executeAction($copyAction);
]]>
</programlisting>
</example>
</sect1>
<sect1 xml:id="language.attributes.syntax">
<title>Syntax von Attributen</title>
<para>
Die Syntax eines Attributs besteht aus mehreren Schlüsselkomponenten. Die
Deklaration eines Attributs beginnt mit <literal>#[</literal> und endet mit
<literal>]</literal>. Sie kann ein oder mehrere Attribute enthalten, die
durch Kommata getrennt sind. Der Name des Attributs kann unqualifiziert,
qualifiziert oder voll qualifiziert sein, wie in
<link linkend="language.namespaces.basics">Grundlagen zu Namensräumen</link>
beschrieben.
Argumente für das Attribut sind optional und werden in Klammern
<literal>()</literal> eingeschlossen. Argumente können nur Literalwerte
oder konstante Ausdrücke sein. Es wird sowohl die Syntax für
Positionsargumente als auch für benannte Argumente unterstützt.
</para>
<para>
Wenn ein Attribut über die Reflection-API angefordert wird, wird sein Name
wie ein Klassenname behandelt und seine Argumente werden an seinen
Konstruktor übergeben. Es wird daher empfohlen, für jedes Attribut eine
Klasse einzuführen.
</para>
<example>
<title>Syntax von Attributen</title>
<programlisting role="php">
<![CDATA[
<?php
// a.php
namespace MyExample;
use Attribute;
#[Attribute]
class MyAttribute
{
const VALUE = 'value';
private $value;
public function __construct($value = null)
{
$this->value = $value;
}
}
// b.php
namespace Another;
use MyExample\MyAttribute;
#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(value: 1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}
#[MyAttribute(1234), MyAttribute(5678)]
class AnotherThing
{
}
]]>
</programlisting>
</example>
</sect1>
<sect1 xml:id="language.attributes.reflection">
<title>Lesen von Attributen mit der Reflection-API</title>
<para>
Mit der von der Reflection-API bereitgestellten Methode
<function>getAttributes</function> kann auf die Attribute von Klassen,
Methoden, Funktionen, Parametern, Eigenschaften und Klassenkonstanten
zugegriffen werden. Diese Methode gibt ein Array von
<classname>ReflectionAttribute</classname>-Instanzen zurück. Diese
Instanzen können nach dem Attributnamen und den Argumenten abgefragt werden
und können verwendet werden, um eine Instanz des dargestellten Attributs zu
instanziieren.
</para>
<para>
Die Trennung der Repräsentation des reflektierten Attributs von seiner
tatsächlichen Instanz ermöglicht eine bessere Kontrolle über die Behandlung
von Fehlern wie fehlende Attributklassen, falsch eingegebene Argumente oder
fehlende Werte. Objekte der Attributklasse werden erst nach dem Aufruf der
Funktion <function>ReflectionAttribute::newInstance</function>
instanziiert, um sicherzustellen, dass die Validierung der Argumente zu
diesem Zeitpunkt erfolgt.
</para>
<example>
<title>Lesen von Attributen mit der Reflection-API</title>
<programlisting role="php">
<![CDATA[
<?php
#[Attribute]
class MyAttribute
{
public $value;
public function __construct($value)
{
$this->value = $value;
}
}
#[MyAttribute(value: 1234)]
class Thing
{
}
function dumpAttributeData($reflection) {
$attributes = $reflection->getAttributes();
foreach ($attributes as $attribute) {
var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
}
}
dumpAttributeData(new ReflectionClass(Thing::class));
/*
string(11) "MyAttribute"
array(1) {
["value"]=>
int(1234)
}
object(MyAttribute)#3 (1) {
["value"]=>
int(1234)
}
*/
]]>
</programlisting>
</example>
<para>
Anstatt alle Attribute der Reflection-Instanz zu durchlaufen, kann auch der
Name einer bestimmten Attributklasse als Argument übergeben werden, um nur
die Attribute dieser Attributklasse abzurufen.
</para>
<example>
<title>Lesen bestimmter Attribute mit der Reflection-API</title>
<programlisting role="php">
<![CDATA[
<?php
function dumpMyAttributeData($reflection) {
$attributes = $reflection->getAttributes(MyAttribute::class);
foreach ($attributes as $attribute) {
var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
}
}
dumpMyAttributeData(new ReflectionClass(Thing::class));
]]>
</programlisting>
</example>
</sect1>
<sect1 xml:id="language.attributes.classes">
<title>Deklaration von Attributklassen</title>
<para>
Es ist empfehlenswert, für jedes Attribut eine eigene Klasse zu definieren.
Im einfachsten Fall genügt eine leere Klasse, in der das Attribut
<literal>#[Attribute]</literal> deklariert wird. Das Attribut kann mit
einer <literal>use</literal>-Anweisung aus dem globalen Namensraum
importiert werden.
</para>
<example>
<title>Einfache Attributklasse</title>
<programlisting role="php">
<![CDATA[
<?php
namespace Example;
use Attribute;
#[Attribute]
class MyAttribute
{
}
]]>
</programlisting>
</example>
<para>
Um die Arten der Deklarationen einzuschränken, auf die ein Attribut
angewendet werden kann, kann eine Bitmaske als erstes Argument an die
<literal>#[Attribute]</literal>-Deklaration übergeben werden.
</para>
<example>
<title>Verwendung der Zielspezifikation, um die Verwendung von Attributen zu beschränken</title>
<programlisting role="php">
<![CDATA[
<?php
namespace Example;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class MyAttribute
{
}
]]>
</programlisting>
<para>
Wenn <classname>MyAttribute</classname> für einen anderen Typ deklariert
wird, wird nun beim Aufruf von
<function>ReflectionAttribute::newInstance</function> eine Exception
ausgelöst.
</para>
</example>
<para>Die folgenden Ziele können angegeben werden:</para>
<simplelist>
<member><constant>Attribute::TARGET_CLASS</constant></member>
<member><constant>Attribute::TARGET_FUNCTION</constant></member>
<member><constant>Attribute::TARGET_METHOD</constant></member>
<member><constant>Attribute::TARGET_PROPERTY</constant></member>
<member><constant>Attribute::TARGET_CLASS_CONSTANT</constant></member>
<member><constant>Attribute::TARGET_PARAMETER</constant></member>
<member><constant>Attribute::TARGET_ALL</constant></member>
</simplelist>
<para>
Standardmäßig kann ein Attribut nur einmal pro Deklaration verwendet
werden. Damit ein Attribut wiederholbar ist, muss es in der Bitmaske der
<literal>#[Attribut]</literal>-Deklaration mit dem Flag
<constant>Attribute::IS_REPEATABLE</constant> angegeben werden.
</para>
<example>
<title>Verwendung von IS_REPEATABLE um ein Attribut mehrfach in einer Deklaration zu erlauben</title>
<programlisting role="php">
<![CDATA[
<?php
namespace Example;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION | Attribute::IS_REPEATABLE)]
class MyAttribute
{
}
]]>
</programlisting>
</example>
</sect1>
</chapter>
<!-- 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
-->