Am 05.06.2026, 23:52:54 schrieb Daniel Scherzer <[email protected] >:
> On Mon, May 4, 2026 at 1:24 PM Daniel Scherzer < > [email protected]> 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. 1. Increases testability of attribute classes that are reflection aware, only need a Reflector instance, no need to have actual attribute example set up. 2. Uses the existing factory method to concentrate the construction logic into one place. 3. avoids static method call with unclear semantics on when „getCurrent()“ returns something. 4. if a user of attributes has to avoid newInstance() (for whatever reason), they can call targetsReflector() themselves. There is no way to „setCurrent()“ reflector however, hiding part of this new behavior in the engine, where it could be 100% user controlled. The only „downside" is that you cant make properties set in targetsReflector() readonly. But from a semantical point of view, the attribute constructor should not have „magic" access to the reflector just to satisfy some own desire to achieve more readonly/value objects. And a class with a constructor calling a static method to get state cannot be called „simple“ or „value object“ in my opinion anyways. Take: #[Entity(repositoryClass: UserRepository::class, table: ‚users’)] #[Column(type: Types::STRING, name: ‚foo‘, nullable: false)] This is just a different way of writing: new Entity(repositoryClass: UserRepository::class, table: ‚users’) new Column(type: Types::STRING, name: ‚foo‘, nullable: false) Basic understanding of this for any PHP developer makes population of the global ReflectionAttribute::getCurrent() seeem „magical“, something we should avoid. greetings Benjamin
