language/attributes.xml
0f14761ba340c6e49797706ac3f0cf1147d97253
0f14761ba340c6e49797706ac3f0cf1147d97253
...
...
@@ -7,37 +7,26 @@
7
7
<?phpdoc print-version-for="attributes"?>
8
8
9
9
<para>
10
-
Attributes allow to add structured, machine-readable metadata information
11
-
on declarations in code: Classes, methods, functions, parameters,
12
-
properties and class constants can be the target of an attribute. The metadata
13
-
defined by attributes can then be inspected at runtime using the
14
-
<link linkend="book.reflection">Reflection
15
-
APIs</link>. Attributes could therefore be thought of as a configuration
16
-
language embedded directly into code.
10
+
PHP attributes provide structured, machine-readable metadata for classes, methods,
11
+
functions, parameters, properties, and constants. They can be inspected at runtime
12
+
via the <link linkend="book.reflection">Reflection API</link>, enabling dynamic
13
+
behavior without modifying code. Attributes provide a declarative way to annotate
14
+
code with metadata.
17
15
</para>
18
-
19
16
<para>
20
-
With attributes the generic implementation of a
21
-
feature and its concrete use in an application can be decoupled. In a way it is
22
-
comparable to interfaces and their implementations. But where
23
-
interfaces and implementations are about code, attributes are about
24
-
annotating extra information and configuration. Interfaces can
25
-
be implemented by classes, yet attributes can also be declared
26
-
on methods, functions, parameters, properties and class constants.
27
-
As such they are more flexible than interfaces.
17
+
Attributes enable the decoupling of a feature's implementation from its usage. While
18
+
interfaces define structure by enforcing methods, attributes provide metadata across multiple
19
+
elements, including methods, functions, properties, and constants. Unlike interfaces,
20
+
which enforce method implementations, attributes annotate code without altering its structure.
21
+
</para>
22
+
<para>
23
+
Attributes can complement or replace optional interface methods by providing metadata instead of
24
+
enforced structure. Consider an <literal>ActionHandler</literal> interface that represents an
25
+
operation in an application. Some implementations may require a setup step while others do not.
26
+
Instead of forcing all classes implementing <literal>ActionHandler</literal> to define a
27
+
<literal>setUp()</literal> method, an attribute can indicate setup requirements. This approach
28
+
increases flexibility, allowing attributes to be applied multiple times when necessary.
28
29
</para>
29
-
30
-
<para>
31
-
A simple example of attribute usage is to convert an interface
32
-
that has optional methods to use attributes. Lets assume an
33
-
<literal>ActionHandler</literal>
34
-
interface representing an operation in an application, where some
35
-
implementations of an action handler require setup and others do not. Instead of requiring all classes
36
-
that implement <literal>ActionHandler</literal> to implement
37
-
a method <literal>setUp()</literal>,
38
-
we use an attribute that can be used instead. One benefit
39
-
of this approach is that we can use the attribute several times.
40
-
</para>
41
30
42
31
<example>
43
32
<title>Implementing optional methods of an interface with Attributes</title>
...
...
@@ -68,7 +57,11 @@ class CopyFile implements ActionHandler
68
57
#[SetUp]
69
58
public function targetDirectoryExists()
70
59
{
71
-
mkdir($this->targetDirectory);
60
+
if (!file_exists($this->targetDirectory)) {
61
+
mkdir($this->targetDirectory);
62
+
} elseif (!is_dir($this->targetDirectory)) {
63
+
throw new RuntimeException("Target directory $this->targetDirectory is not a directory");
64
+
}
72
65
}
73
66
74
67
public function execute()
...
...
@@ -108,21 +101,21 @@ executeAction($copyAction);
108
101
<title>Attribute syntax</title>
109
102
110
103
<para>
111
-
There are several parts to the attributes syntax. First, attribute
112
-
declaration are always enclosed with a starting
113
-
<literal>#[</literal> and a corresponding ending
114
-
<literal>]</literal>. Inside, one or many attributes are listed,
115
-
seperated by comma. The attribute name is an unqualified, qualified
116
-
or fully-qualified name as described in <link linkend="language.namespaces.basics">Using Namespaces Basics</link>.
117
-
Arguments to the attribute are optional, but are enclosed in the usual parenthesis <literal>()</literal>.
118
-
Arguments to attributes can only be literal values or constant expressions. Both positional and
119
-
named arguments syntax can be used.
104
+
Attribute syntax consists of several key components. An attribute
105
+
declaration starts with <literal>#[</literal> and ends with
106
+
<literal>]</literal>. Inside, one or more attributes can be listed,
107
+
separated by commas. The attribute name can be unqualified, qualified,
108
+
or fully-qualified, as described in <link linkend="language.namespaces.basics">Using Namespaces Basics</link>.
109
+
Arguments to the attribute are optional and enclosed in parentheses
110
+
<literal>()</literal>. Arguments can only be literal values or constant
111
+
expressions. Both positional and named argument syntax are supported.
120
112
</para>
121
113
122
114
<para>
123
-
Attribute names and their arguments are resolved to a class and the arguments are passed to its constructor,
124
-
when an instance of the attribute is requested through the Reflection API. As such
125
-
a class should be introduced for each attribute.
115
+
Attribute names and their arguments are resolved to a class, and the arguments
116
+
are passed to its constructor when an instance of the attribute is requested
117
+
through the Reflection API. Therefore, it is recommended to introduce a class
118
+
for each attribute.
126
119
</para>
127
120
128
121
<example>
...
...
@@ -180,17 +173,19 @@ class AnotherThing
180
173
<title>Reading Attributes with the Reflection API</title>
181
174
182
175
<para>
183
-
To access attributes from classes, methods, functions, parameters, properties and class constants,
184
-
the Reflection API provides the method <function>getAttributes</function> on each of the corresponding
185
-
Reflection objects. This method returns an array of <classname>ReflectionAttribute</classname> instances
186
-
that can be queried for attribute name, arguments and to instantiate an instance of the represented attribute.
176
+
To access attributes from classes, methods, functions, parameters, properties,
177
+
and class constants, use the <function>getAttributes</function> method provided
178
+
by the Reflection API. This method returns an array of <classname>ReflectionAttribute</classname>
179
+
instances. These instances can be queried for the attribute name, arguments, and
180
+
can be used to instantiate an instance of the represented attribute.
187
181
</para>
188
182
189
183
<para>
190
-
This separation of reflected attribute representation from actual instance increases control of the programmer
191
-
to handle errors regarding missing attribute classes, mistyped or missing arguments. Only after
192
-
calling <function>newInstance</function>, objects of the attribute class are instantiated and the correct matching of arguments
193
-
is validated, not earlier.
184
+
Separating the reflected attribute representation from its actual instance provides more
185
+
control over error handling, such as missing attribute classes, mistyped arguments,
186
+
or missing values. Objects of the attribute class are instantiated only after calling
187
+
<function>ReflectionAttribute::newInstance</function>, ensuring that argument validation
188
+
occurs at that point.
194
189
</para>
195
190
196
191
<example>
...
...
@@ -244,9 +239,9 @@ object(MyAttribute)#3 (1) {
244
239
</example>
245
240
246
241
<para>
247
-
Instead of iterating all attributes on the reflection instance, only those
248
-
of a particular attribute class can be
249
-
retrieved by passing the searched attribute class name as argument.
242
+
Instead of iterating over all attributes on the reflection instance,
243
+
you can retrieve only those of a specific attribute class by passing
244
+
the attribute class name as an argument.
250
245
</para>
251
246
252
247
<example>
...
...
@@ -266,7 +261,7 @@ function dumpMyAttributeData($reflection) {
266
261
}
267
262
}
268
263
269
-
dumpAttributeData(new ReflectionClass(Thing::class));
264
+
dumpMyAttributeData(new ReflectionClass(Thing::class));
270
265
]]>
271
266
</programlisting>
272
267
</example>
...
...
@@ -276,13 +271,14 @@ dumpAttributeData(new ReflectionClass(Thing::class));
276
271
<title>Declaring Attribute Classes</title>
277
272
278
273
<para>
279
-
While not strictly required it is recommended to create an actual class for every attribute.
280
-
In the most simple case only an empty class is needed with the <literal>#[Attribute]</literal> attribute declared
281
-
that can be imported from the global namespace with a use statement.
274
+
It is recommended to define a separate class for each attribute. In the simplest
275
+
case, an empty class with the <literal>#[Attribute]</literal> declaration is sufficient.
276
+
The attribute can be imported from the global namespace using a <literal>use</literal>
277
+
statement.
282
278
</para>
283
279
284
280
<example>
285
-
<title>Using target specification to restrict where attributes can be used</title>
281
+
<title>Simple Attribute Class</title>
286
282
287
283
<programlisting role="php">
288
284
<![CDATA[
...
...
@@ -301,12 +297,13 @@ class MyAttribute
301
297
</example>
302
298
303
299
<para>
304
-
To restrict the type of declaration an attribute can be assigned to, a bitmask can be passed as the first
305
-
argument to the <literal>#[Attribute]</literal> declaration.
300
+
To restrict the types of declarations an attribute can be applied to,
301
+
pass a bitmask as the first argument to the <literal>#[Attribute]</literal>
302
+
declaration.
306
303
</para>
307
304
308
305
<example>
309
-
<title>Simple Attribute Class</title>
306
+
<title>Using target specification to restrict where attributes can be used</title>
310
307
311
308
<programlisting role="php">
312
309
<![CDATA[
...
...
@@ -329,9 +326,23 @@ class MyAttribute
329
326
</para>
330
327
</example>
331
328
329
+
<para>The following targets can be specified:</para>
330
+
331
+
<simplelist>
332
+
<member><constant>Attribute::TARGET_CLASS</constant></member>
333
+
<member><constant>Attribute::TARGET_FUNCTION</constant></member>
334
+
<member><constant>Attribute::TARGET_METHOD</constant></member>
335
+
<member><constant>Attribute::TARGET_PROPERTY</constant></member>
336
+
<member><constant>Attribute::TARGET_CLASS_CONSTANT</constant></member>
337
+
<member><constant>Attribute::TARGET_PARAMETER</constant></member>
338
+
<member><constant>Attribute::TARGET_ALL</constant></member>
339
+
</simplelist>
340
+
332
341
<para>
333
-
By default an attribute can only be used once per declaration. If the attribute should be repeatable on declarations it must
334
-
be specified as part of the bitmask to the <literal>#[Attribute]</literal> declaration.
342
+
By default, an attribute can only be used once per declaration. To allow
343
+
an attribute to be repeatable, specify it in the bitmask of the
344
+
<literal>#[Attribute]</literal> declaration using the
345
+
<constant>Attribute::IS_REPEATABLE</constant> flag.
335
346
</para>
336
347
337
348
<example>
338
349