Hi internals,
The #[\Attribute] attribute is used to mark classes as being usable as
attributes. It currently does not trigger any error if added to a trait,
interface, enum, or abstract class. However, if any of those were used as
an attribute, calling ReflectionAttribute::newInstance() would fail; if you
are not going to call ReflectionAttribute::newInstance(), then you don't
really need to mark the trait/interface/enum/abstract class as an attribute.
I have proposed https://github.com/php/php-src/pull/19154 to add validation
to the #[Attribute] attribute, and it was suggested that I post here on the
mailing list in case there were any objections. So, are there?
-Daniel
Hi internals,
The #[\Attribute] attribute is used to mark classes as being usable as
attributes. It currently does not trigger any error if added to a
trait, interface, enum, or abstract class. However, if any of those
were used as an attribute, calling ReflectionAttribute::newInstance()
would fail; if you are not going to call
ReflectionAttribute::newInstance(), then you don't really need to mark
the trait/interface/enum/abstract class as an attribute.I have proposed https://github.com/php/php-src/pull/19154 to add
validation to the #[Attribute] attribute, and it was suggested that I
post here on the mailing list in case there were any objections. So,
are there?-Daniel
I just checked AttributeUtils, and I don't think this will cause an issue. I do support interfaces and opt-in inheritance, but I don't believe it actually tags an interface with #[Attribute] anywhere.
--Larry Garfield
Hi internals,
The #[\Attribute] attribute is used to mark classes as being usable as attributes. It currently does not trigger any error if added to a trait, interface, enum, or abstract class. However, if any of those were used as an attribute, calling ReflectionAttribute::newInstance() would fail; if you are not going to call ReflectionAttribute::newInstance(), then you don't really need to mark the trait/interface/enum/abstract class as an attribute.
I have proposed https://github.com/php/php-src/pull/19154 to add validation to the #[Attribute] attribute, and it was suggested that I post here on the mailing list in case there were any objections. So, are there?
-Daniel
Since \Attribute itself is an attribute, I wouldn’t expect it to be validated until newInstance is called. In fact, if I remember correctly from the original discussion, this was done deliberately so it would be forward compatible. Further, by making it compile-time validated, I would be misled to think my own attributes would be validated at compile time (which I think is a better solution than hodgepodging our way there).
— Rob
Hey,
if you are not going to call ReflectionAttribute::newInstance(), then you don't
really need to mark the trait/interface/enum/abstract class as an attribute.
Personally I never knew the #[\Attribute]
is only required to do ->newInstance()
.
The docs make it seem like it’s a boilerplate to have an attribute at all: https://www.php.net/manual/en/language.attributes.overview.php
And the documented example does not call newInstance
although the attribute is defined with #[Attribute]
.
I’m also confused as the example created by Ilija https://3v4l.org/8Lih3#v8.4.10 that would supposedly break does not include #[Attribute]
at all. But it includes an enum being used as attribute without it using the label itself. So what would actually break? Using enums as attributes or declaring them as such?
Btw while reviewing the docs https://www.php.net/manual/en/language.attributes.classes.php
I noticed that
It is recommended to define a separate class for each attribute.
Recommended as opposed to what other options? I don’t think I can use a random string as an attribute without defining it, right? So what is this recommendation steering me away from?
BR,
Juris
Hey,
if you are not going to call ReflectionAttribute::newInstance(), then you don't
really need to mark the trait/interface/enum/abstract class as an attribute.Personally I never knew the
#[\Attribute]
is only required to do->newInstance()
.The docs make it seem like it’s a boilerplate to have an attribute at all: https://www.php.net/manual/en/language.attributes.overview.php
And the documented example does not callnewInstance
although the attribute is defined with#[Attribute]
.I’m also confused as the example created by Ilija https://3v4l.org/8Lih3#v8.4.10 that would supposedly break does not include
#[Attribute]
at all. But it includes an enum being used as attribute without it using the label itself. So what would actually break? Using enums as attributes or declaring them as such?Btw while reviewing the docs https://www.php.net/manual/en/language.attributes.classes.php
I noticed thatIt is recommended to define a separate class for each attribute.
Recommended as opposed to what other options? I don’t think I can use a random string as an attribute without defining it, right? So what is this recommendation steering me away from?
BR,
Juris
Hi Juris,
You can use any identifier you’d like as an attribute, so long as you never try to get an instance of them. Since you are already reflecting on them, instead of getting an instance, you can just get the arguments and do whatever you want. We actually ended up doing this on an internal project at my last job. It was pretty powerful.
— Rob
Le 25 juil. 2025 à 18:37, Daniel Scherzer daniel.e.scherzer@gmail.com a écrit :
Hi internals,The #[\Attribute] attribute is used to mark classes as being usable as attributes. It currently does not trigger any error if added to a trait, interface, enum, or abstract class. However, if any of those were used as an attribute, calling ReflectionAttribute::newInstance() would fail; if you are not going to call ReflectionAttribute::newInstance(), then you don't really need to mark the trait/interface/enum/abstract class as an attribute.
I have proposed https://github.com/php/php-src/pull/19154 to add validation to the #[Attribute] attribute, and it was suggested that I post here on the mailing list in case there were any objections. So, are there?
-Daniel
Hi,
Validating more precisely the target of #[Atrribute] is reasonable. Now, observing that there are several internal attributes that may benefit this capability (e.g. #[Attribute], #[AllowDynamicProperties], #[Deprecated] on traits as currenty voted on), I wonder if we can also expose this capability to user-defined attributes? Concretely, there could be the following additional constants:
- Attribute::TARGET_INTERFACE
- Attribute::TARGET_ABSTRACT_CLASS
- Attribute::TARGET_TRAIT
- Attribute::TARGET_ENUM
- Attribute::TARGET_REGULAR_CLASS
and Attribute::TARGET_CLASS would be equal to the result of combining all of those with the |
operator.
—Claude
—Claude