On Tue, Jul 6, 2021 at 2:30 PM Nicolas Grekas <nicolas.grekas+...@gmail.com> wrote:
> > > > This is not 100% correct, you can have an attribte #[Foo(Foo::class)] >> and >> > > then calling ReflectionAttribute::getArguments would also require to >> > > resolve the type Foo. So this is not different than what could happen >> > right >> > > now already. >> > >> > >> > Despite its name, "::class" doesn't care about class definitions, it >> > just performs a string substitution based on the "namespace" and "use" >> > statements in the current file. >> > >> > In most cases, that happens entirely at compile time, so the following >> > two source files compile identically: >> > >> >> Hah, I realized after sending the example was bad :) I should have used an >> example using actual constants (vs magic ones): >> >> #[Foo(Foo::BAR)] >> >> This would trigger autoloading and resolving during getArguments() >> > > > Right! > > Extending on my proposal, getUninitializedArguments() could return a > ReflectionConstant in place of such values. > This doesn't extend to any more complex scenario: It's not just #[Foo(A::B)], it could also be #[Foo(A::FLAG_1 | A::FLAG_2)] and so on. The only way to do this is to go all the way back to Dmitry's attribute proposal (https://wiki.php.net/rfc/attributes) which allows fetching the AST of attribute arguments. That could represent arbitrary arguments without evaluating them. (In fact, that proposal also allowed attribute arguments that PHP cannot constant-evaluate at all.) I also think that viewing this as "nested attributes" is not quite the right way to think about it. Yes, the Assert\All use case is nested attributes, but that's just a special case. More generally this just allows you to use an object as an attribute argument, and that object does not necessarily have to be an attribute itself. To give a silly example, if we were to write argument and return types as attributes, you could have something like #[ReturnType(new IntersectionType(Foo::class, Bar::class))], where IntersectionType is just the representation of a particular type, but is not (and shouldn't be) an attribute itself. Regards, Nikita