Re: [RFC idea] Target-aware attributes
| From: | Larry Garfield | Date: | Thu, 03 Jul 2025 21:38:58 +0000 |
| Subject: | Re: [RFC idea] Target-aware attributes | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-127870@lists.php.net to get a copy of this message | ||
On Thu, Jul 3, 2025, at 12:54 PM, Andreas Hennings wrote:
>> > A setter method injection is what I did in AttributeUtils, because it was the only
>> > real option. Alternatively, I suppose core could use property setter injection (either a magically
>> > named property like $__reflector, or a property that itself has an attribute on it, etc.). That
>> > would allow it to be set before the constructor is called, and with property hooks would allow
>> > processing either immediately or later in the constructor. The downside here is that Attribute are,
>> > generally, serializable, but a Reflection object is not. So if someone wanted a serializable
>> > attribute they would have to accept the property, use it, and then remember to unset it at some
>> > point. That's clumsy.
>> >
>> > --Larry Garfield
>> >
>>
>> As someone that's written yet another userland "solution" for this problem,
>> I have an alternative solution, based somewhat on an internalised concept of "never store
>> Reflectors".
>>
>> Introduce an interface "ReflectorAttribute" (bike shedding to come); which
>> accepts a single Reflector argument.
>>
>> If the attribute implements the interface, the method is called immediately following
>> instantiation.
>
> Yep, this is the "method injection" mentioned by Larry, or what I
> referred to as "setter injection".
> I have not seen your library, but I assume that's where it is going.
Yes, that is what AttributeUtils does today, almost exactly. From the docs:
#[\Attribute]
class AttribWithName implements FromReflectionClass
{
public readonly string $name;
public function __construct(?string $name = null)
{
if ($name) {
$this->name = $name;
}
}
public function fromReflection(\ReflectionClass $subject): void
{
$this->name ??= $subject->getShortName();
}
}
(There's a different interface for each type of thing an attribute can be put on because the
parameter type is different.)
--Larry Garfield