-
Notifications
You must be signed in to change notification settings - Fork 81
Expand file tree
/
Copy pathattributes.xml
More file actions
395 lines (321 loc) · 12.1 KB
/
attributes.xml
File metadata and controls
395 lines (321 loc) · 12.1 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
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 0f14761ba340c6e49797706ac3f0cf1147d97253 Maintainer: mumumu Status: ready -->
<chapter xml:id="language.attributes" xmlns="http://docbook.org/ns/docbook">
<title>アトリビュート</title>
<sect1 xml:id="language.attributes.overview">
<title>アトリビュートの概要</title>
<?phpdoc print-version-for="attributes"?>
<para>
PHP のアトリビュートは、クラス、メソッド、関数、パラメータ、プロパティ、定数に、
構造化され、かつマシンが読み取り可能なメタデータを提供します。
これらは <link linkend="book.reflection">リフレクション API</link> を介して実行時に検査でき、
コードを変更することなく動的な振る舞いを可能にします。
アトリビュートは、宣言的な方法でコードにメタデータの注釈を付ける方法を提供します。
</para>
<para>
アトリビュートは、機能の実装と利用を分離できるようにします。
インターフェイスがメソッドを強制することで構造を定義するのに対し、
アトリビュートはメソッド、関数、プロパティ、定数を含む、
複数の要素にわたってメタデータを提供します。
インターフェイスがメソッドの実装を強制するのとは異なり、
アトリビュートはコードの構造を変更することなく注釈を付けます。
</para>
<para>
アトリビュートは、強制された構造の代わりにメタデータを提供することで、
オプションのインターフェイスメソッドを補完または置き換えることができます。
アプリケーションでの操作を表す <literal>ActionHandler</literal> インターフェイスを考えてみましょう。
一部の実装ではセットアップ手順が必要な場合がありますが、必要ない場合もあります。
<literal>ActionHandler</literal> を実装するすべてのクラスに
<literal>setUp()</literal> メソッドの定義を強制する代わりに、
アトリビュートを使用してセットアップ要件を示すことができます。
このアプローチは柔軟性を高め、必要に応じてアトリビュートを複数回適用できます。
</para>
<example>
<title>アトリビュートを使い、インターフェイスのオプションのメソッドを実装する</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("File does not exist");
}
}
#[SetUp]
public function targetDirectoryExists()
{
if (!file_exists($this->targetDirectory)) {
mkdir($this->targetDirectory);
} elseif (!is_dir($this->targetDirectory)) {
throw new RuntimeException("Target directory $this->targetDirectory is not a directory");
}
}
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>アトリビュートの文法</title>
<para>
アトリビュートの文法は、いくつかの重要な要素で構成されています。
アトリビュートの宣言は <literal>#[</literal> で始まり、<literal>]</literal> で終わります。
その内部には、1つ以上のアトリビュートをカンマで区切って並べることができます。
アトリビュート名は、<link linkend="language.namespaces.basics">名前空間の基礎</link> で説明されているように、
非修飾名、修飾名、または完全修飾名にすることができます。
アトリビュートへの引数はオプションで、括弧 <literal>()</literal> で囲みます。
引数にはリテラル値または定数式のみを指定できます。
位置引数と名前付き引数の両方の構文がサポートされています。
</para>
<para>
アトリビュート名とその引数はクラスに解決され、
リフレクション API を介してアトリビュートのインスタンスが要求されると、
引数がそのコンストラクタに渡されます。
したがって、各アトリビュートに対してクラスを導入することをお勧めします。
</para>
<example>
<title>アトリビュートの文法</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>リフレクションAPI を使ってアトリビュートを読み取る</title>
<para>
クラス、メソッド、関数、パラメータ、プロパティ、クラス定数からアトリビュートにアクセスするには、
リフレクション API が提供する <function>getAttributes</function> メソッドを使用します。
このメソッドは <classname>ReflectionAttribute</classname> インスタンスの配列を返します。
これらのインスタンスは、アトリビュート名、引数を問い合わせることができ、
表現されたアトリビュートのインスタンスをインスタンス化するために使用できます。
</para>
<para>
リフレクションされたアトリビュートの表現を実際のインスタンスから分離することで、
存在しないアトリビュートクラス、型指定ミス、値の不足など、
エラー処理をより詳細に制御できます。
アトリビュートクラスのオブジェクトは <function>ReflectionAttribute::newInstance</function>
を呼び出した後にのみインスタンス化され、その時点で引数の検証が行われます。
</para>
<example>
<title>リフレクション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>
リフレクションインスタンスのすべてのアトリビュートをループする代わりに、
アトリビュートクラス名を引数として渡すことで、
特定のアトリビュートのクラスだけを取得できます。
</para>
<example>
<title>リフレクション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>アトリビュートクラスを宣言する</title>
<para>
アトリビュートごとに個別のクラスを定義することをお勧めします。
最も単純なケースでは、<literal>#[Attribute]</literal> 宣言を持つ空のクラスで十分です。
このアトリビュートは、<literal>use</literal> 文を使用してグローバル名前空間からインポートできます。
</para>
<example>
<title>単純なアトリビュートクラスの例</title>
<programlisting role="php">
<![CDATA[
<?php
namespace Example;
use Attribute;
#[Attribute]
class MyAttribute
{
}
]]>
</programlisting>
</example>
<para>
アトリビュートを適用できる宣言の種類を制限するには、
<literal>#[Attribute]</literal> 宣言の最初の引数としてビットマスクを渡します。
</para>
<example>
<title>アトリビュートを使える場所を限定するために、ターゲットとなるクラスを作る</title>
<programlisting role="php">
<![CDATA[
<?php
namespace Example;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class MyAttribute
{
}
]]>
</programlisting>
<para>
<classname>MyAttribute</classname> を別の型で宣言すると、
<function>ReflectionAttribute::newInstance</function> の呼び出し時に例外がスローされます。
</para>
</example>
<para>ビットマスクには、以下が指定できます:</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>
デフォルトでは、アトリビュートは宣言ごとに1回しか使用できません。
アトリビュートを繰り返し可能にするには、
<literal>#[Attribute]</literal> 宣言のビットマスクで
<constant>Attribute::IS_REPEATABLE</constant> フラグを指定します。
</para>
<example>
<title>宣言時にアトリビュートを複数回使えるように、IS_REPEATABLE を使う</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
-->