7
7
<?phpdoc print-version-for =" attributes" ?>
8
8
9
9
<para >
10
- Attributes offer the ability 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. Let's 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
- an attribute can be used. 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 >
@@ -112,21 +101,21 @@ executeAction($copyAction);
112
101
<title >Attribute syntax</title >
113
102
114
103
<para >
115
- There are several parts to the attributes syntax. First, an attribute
116
- declaration is always enclosed with a starting
117
- <literal >#[</literal > and a corresponding ending
118
- <literal >]</literal >. Inside, one or many attributes are listed,
119
- separated by comma. The attribute name is an unqualified, qualified
120
- or fully-qualified name as described in <link linkend =" language.namespaces.basics" >Using Namespaces Basics</link >.
121
- Arguments to the attribute are optional, but are enclosed in the usual parenthesis <literal >()</literal >.
122
- Arguments to attributes can only be literal values or constant expressions. Both positional and
123
- 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.
124
112
</para >
125
113
126
114
<para >
127
- Attribute names and their arguments are resolved to a class and the arguments are passed to its constructor,
128
- when an instance of the attribute is requested through the Reflection API. As such
129
- 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.
130
119
</para >
131
120
132
121
<example >
@@ -184,17 +173,19 @@ class AnotherThing
184
173
<title >Reading Attributes with the Reflection API</title >
185
174
186
175
<para >
187
- To access attributes from classes, methods, functions, parameters, properties and class constants,
188
- the Reflection API provides the method <function >getAttributes</function > on each of the corresponding
189
- Reflection objects. This method returns an array of <classname >ReflectionAttribute</classname > instances
190
- 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.
191
181
</para >
192
182
193
183
<para >
194
- This separation of reflected attribute representation from actual instance increases control of the programmer
195
- to handle errors regarding missing attribute classes, mistyped or missing arguments. Only after
196
- calling <function >ReflectionAttribute::newInstance</function >, objects of the attribute class are instantiated and the correct matching of arguments
197
- 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.
198
189
</para >
199
190
200
191
<example >
@@ -248,9 +239,9 @@ object(MyAttribute)#3 (1) {
248
239
</example >
249
240
250
241
<para >
251
- Instead of iterating all attributes on the reflection instance, only those
252
- of a particular attribute class can be
253
- 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.
254
245
</para >
255
246
256
247
<example >
@@ -280,9 +271,10 @@ dumpMyAttributeData(new ReflectionClass(Thing::class));
280
271
<title >Declaring Attribute Classes</title >
281
272
282
273
<para >
283
- While not strictly required it is recommended to create an actual class for every attribute.
284
- In the most simple case only an empty class is needed with the <literal >#[Attribute]</literal > attribute declared
285
- 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.
286
278
</para >
287
279
288
280
<example >
@@ -305,8 +297,9 @@ class MyAttribute
305
297
</example >
306
298
307
299
<para >
308
- To restrict the type of declaration an attribute can be assigned to, a bitmask can be passed as the first
309
- 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.
310
303
</para >
311
304
312
305
<example >
@@ -346,8 +339,10 @@ class MyAttribute
346
339
</simplelist >
347
340
348
341
<para >
349
- By default an attribute can only be used once per declaration. If the attribute should be repeatable on declarations it must
350
- 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.
351
346
</para >
352
347
353
348
<example >
0 commit comments