Re: Re: [RFC] [Discussion] Add ReflectionAttribute::getCurrent()
| From: | Larry Garfield | Date: | Sun, 07 Jun 2026 12:31:53 +0000 |
| Subject: | Re: Re: [RFC] [Discussion] Add ReflectionAttribute::getCurrent() | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131163@lists.php.net to get a copy of this message | ||
On Sun, Jun 7, 2026, at 7:07 AM, Benjamin Außenhofer wrote:
> Am 07.06.2026, 06:29:17 schrieb Benjamin Außenhofer <kontakt@beberlei.de>:
>>
>>
>> Am 05.06.2026, 23:52:54 schrieb Daniel Scherzer <daniel.e.scherzer@gmail.com>:
>>> On Mon, May 4, 2026 at 1:24 PM Daniel Scherzer <daniel.e.scherzer@gmail.com>
>>> wrote:
>>>> Hi internals,
>>>>
>>>> I'd like to start the discussion for a new RFC about adding a new method,
>>>> ReflectionAttribute::getCurrent(), to access the current reflection target of an attribute.
>>>>
>>>> * RFC:
>>>> https://wiki.php.net/rfc/reflectionattribute-getcurrent
>>>> * Implementation:
>>>> https://github.com/php/php-src/pull/21440
>>>>
>>>> Thanks,
>>>> -Daniel
>>>
>>> Barring any additional feedback, I plan to open the vote on this in the next few days.
>>>
>>> -Daniel
>>
>> Hi Daniel,
>>
>> sorry i could not find the time to reply earlier. the idea in general is good, but i still
>> very much disagree about the static method to get the reflector context.
>>
>> An attribute is often passed around as a configuration object or hierachy down to other
>> services, for example in Symfony validator.
>>
>> #[NotNull]
>> public $foo;
>>
>> $validator = new NotNullValidator();
>> $validator->validate($instance->foo, $notNullAttribute);
>>
>> For testing purposes it makes sense in these examples to construct the attributes directly
>> using new SomeAttribute(). Now with this proposal, you need to be careful and know from the outside,
>> when that is possible, or when you need to call it through ReflectionAttribute::newInstance().. The
>> coupling becomes very strong suddenly.
>>
>> When you create the attributes yourself and without calling newInstance(), then the method
>> does not work at all:
>>
>> $class = $reflectionAttribute->getName();
>> new $class(…$this->getArguments())); // ReflectionAttribute::getCurrent() returns null
>> in this ctor.
>>
>> This is something the RFC is not clear about fully. There is the definition of an
>> „attribute constructor“, but a constructor of an Attribute can be called many ways. This
>> proposal is about the ctor only when called through newInstance().
>>
>> I propose instead that we extend the newInstance() factory method, to be more versatile,
>> and use the benefit here that we already have a factory method where we can place this logic:
>>
>> <?php
>>
>> interface ReflectionAwareAttribute
>> {
>> public function targetsReflector(Reflector $reflector);
>> }
>>
>> class ReflectionAttribute
>> {
>> public function newInstance()
>> {
>> $class = $this->getName();
>> $instance = new $class(...$this->getArguments());
>>
>> if ($instance instanceof ReflectionAwareAttribute) {
>> $instance->targetsReflector($this);
>> }
>>
>> return $instance;
>> }
>> }
>>
>> This is much cleaner OOP wise.
That is essentially what AttributeUtils does now. If you tag your class attribute with the
FromReflectionClass, then the reflection object is passed to the fromReflection() method right after
the constructor.
I forget why people objected to that approach when this was discussed last year, but there were some
who weren't fans.
Personally, I'd be OK with that alternative. It would still let me greatly simplify the
AttributeUtils API and reduce the number of moving parts.
The catch, however, is that the type of the parameter becomes an issue. Reflector is valid, but too
generic. This RFC proposes a new interface for reflection objects that can have attributes, which
is good, but wouldn't add much here.
What we really want is... generics. :-)
interface ReflectionAware<T: Reflector> { ... }
#[Attribute(Attribute::TARGET_CLASS|Attribute::TARGET_METHOD)]
class MyAttrib implements ReflectionAware<ReflectionClass|ReflectionMethod> {
// ...
}
--Larry Garfield