Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130772 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id D7AD11A00BC for ; Mon, 4 May 2026 21:59:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1777931976; bh=bfUfN9L6SemecJ4Lf5RL2+CnzGcYVN0HsFDukJWw4qA=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=dEh4zqby2ioWODva5ppp7flvJ+WibT/HeD2w81/5CG4GYC+VJEAWAZvWDQOxHrTI7 NnyNYThQsG11ucw9ay4cC9DIyr0AQu2t5kv+jA/ChTxAquMM3uzF8A8WsyMh+cpdqE wDWxBjK4s2n42aaDtSrBf+9lA59VW3rQqrKh9YUMXvdh+l5HlfybAgII5Ji90RKI+z BBEUPAq2DocrwzhNvY5QOmvG7EUoWXt8DkO6B9DReIaVQyFt/sTITsKQCji6zEOZz/ YpHcvaZjcuuN9OpDNZbezw3wO5rUwfQzkiMnkoF/PpVyQpHPvFOEW7JpBX6E493p5P MswVufpihiMvA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 44D9D180048 for ; Mon, 4 May 2026 21:59:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-yx1-f50.google.com (mail-yx1-f50.google.com [74.125.224.50]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 4 May 2026 21:59:31 +0000 (UTC) Received: by mail-yx1-f50.google.com with SMTP id 956f58d0204a3-64d5a7926cfso4446916d50.2 for ; Mon, 04 May 2026 14:59:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1777931966; cv=none; d=google.com; s=arc-20240605; b=bberbbOacZztcnpQNXZVaQxJTSdiBmge+l4ey+I/ZubuhmhezjeDOFUJETUaohl7Sj HuSW0kGM+B0ZlvJRa5WXHZKb3Lq/hZmQ3EGy0ufHEubqw+uCA4yOlFkVxydHzJ0oY2RH Sm+0cp2p1tawUdBo0Nx+KyzRf8N/z3D08IPu4z+YLNpcgmea0Uj3xxtUnbKz5T9WeDk/ 50hsqqNCNUDVtfpsKHrXuzEq1bqG0PIfgOQqUMfsLQhqy/jKvHpqse2L1/pTeMSjme7i wxlk9avphIpDjK0eEuVsTjz0bA2CIyb2lYWrg2oOZYrx22hb2/ZvdjJJOk6SuVptTKKA F0HQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=xQeIseN8UEjyu1ZkIkx6i8sP3bBJ6O3yPBiGp3CRl2w=; fh=a2UmS3UPhOQSEgu4f/utmrOFMcvVWR9qKLeZmQUqoNc=; b=cqHu8dPtyPJV/vaqbveSxZw8yB286H09zE8xilrOG8yVO+ZD1cS15yYFZLTSMtiORL LVdJobZXQpapoHv+feg/dvKPldw+xzWH5OzXnCCZeYK54iCWlXZjjGCQxsVId5R+AaoD R0PtaHCm8PjavdIC8CumF6V0enb2OqElcMo4JpevYnhkXWNJ3QTkDjLjCbd2Pg0ER7Z2 HYmLJ2n8ZNnkY8IP0QBM4cdwmO27fr1jhX6yL9MBUx75gFvLjkubC1hJf2jVXMC5+NLP LXSyuOQx1vImwiubdykGaDdRianPoCifegn9R4Eu1hJo+vTTD4F9xkGWyI2nam0bRodg 1JCA==; darn=lists.php.net ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777931966; x=1778536766; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=xQeIseN8UEjyu1ZkIkx6i8sP3bBJ6O3yPBiGp3CRl2w=; b=R2/Nrcp5ukJ41FM1Lc4cUqQN5kl72XlrQF0brg4GK83zxyIahnhwHNuGJGi10m1WFc 8UxDdCuJZjQVpozAAZVKJOOg0+7xTAFypevPOExfIL793axoM86fs6BRV2dBIaNqXd11 jKiz7VED7v4tRNOyeWNCQ6QPJA18vxIg8kAlEehm2mELCAZ2IkxwrpBlsmJsk9X6qzNW QRP/iqMayxQ1LmqU4iJO13Z7uTq0la7qs+55XbF8Gm4Omda7RqTt2RLHsXZTf3rh97Sw r8APhU+G1Z6XJkxHD+rIl3oyCqibrbwCX6u52kahjwo6djBGKOABrudKgt6aVp0PcKVj AwiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777931966; x=1778536766; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xQeIseN8UEjyu1ZkIkx6i8sP3bBJ6O3yPBiGp3CRl2w=; b=l+KttfsJLGsccvzIzmFd1XW0+6RQJHcy1wOhED0PXt9if2plmvbwbbDQ3X3vIHoQTa 5uasyPtgKTso/c4S1ojf5nf/9g66u2+2TUZBSwItTct784DPl4rEW3yMa4XmWRdO/SF5 l25yeSOgwurTux3L/Xc7afF9FnL1odhiwh9Fh38y7nihVV4fKAN5ZBREWQT8hN0o03pc 7tmVQt8rWL7EqoYfUsARomF7CLZXZDh0GOGeQpZ22G54rj1OLrkWUobfcIZHNT0ptYC3 VcjRH4dsQFfw6Xi8XWW/eWf3XFfw9GE/TxYR+SneGp0J9xRQJlQUYDcU9yzLtYdoxtBo wFpA== X-Gm-Message-State: AOJu0YzA2Ra1oXa/EaMEsJsg+w61QVfvm6UnCPnTftALy+2jrcuKqGFw ROoNx0p3WrQxHnCsY2Nk6YWfoI32wcPQzvL2iMdgctBKZstxmSQ1aSOAAxMh6pHV1Oxfft3z3MZ Wc/C3fFGijCne/tOpxovMagUWjSvQ0ts= X-Gm-Gg: AeBDievrdIN5Us7HSfbIeSgp9eTpY3CyaIVLTPUdGuUX4lK79p24m9RuhSslnGFUDxX x+yj+hHunwPr9sxIoXjYptxDk4eIpJmaWipl902COyHSrU2c1P9ltj8MVZPH4q5bjfclnIKvK9n 151tiVszlqLocaV4ZzkIE0CRfur9M5b5+nVXckfz9RV66vrSSy2qfieWWnJvdQUyrddqVIBWzVV BIAbORy58leXs9UHSIKuzFo0DY7C3noBPKSWSntG1XKMm7E+6ABfZg1pbG2yOQgPKyzuxUs+xWG B6tI/cuk/silm5Gv1g== X-Received: by 2002:a05:690c:388:b0:7bd:9899:f912 with SMTP id 00721157ae682-7bd9899fe69mr50544017b3.29.1777931966205; Mon, 04 May 2026 14:59:26 -0700 (PDT) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Mon, 4 May 2026 14:58:52 -0700 X-Gm-Features: AVHnY4LTg2GRUFn_xY6-Y_b28CYcI_DgjorNvnb98C1NUTYNrYbDVxP-PXjoncs Message-ID: Subject: Re: [PHP-DEV] [RFC] [Discussion] Add ReflectionAttribute::getCurrent() To: Rob Landers Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="00000000000047d32c0651050b82" From: daniel.e.scherzer@gmail.com (Daniel Scherzer) --00000000000047d32c0651050b82 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Mon, May 4, 2026 at 2:47=E2=80=AFPM Rob Landers wrot= e: > > > On Mon, May 4, 2026, at 23:22, Daniel Scherzer wrote: > > > On Mon, May 4, 2026 at 2:13=E2=80=AFPM Derick Rethans wr= ote: > > On 4 May 2026 21:24:39 BST, Daniel Scherzer > 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 targ= et > >of an attribute. > > > >* RFC: https://wiki.php.net/rfc/reflectionattribute-getcurrent > > > "a new static method, ReflectionAttribute::getCurrent(), that, when calle= d > from an attribute constructor, returns a reflection object corresponding = to > what the attribute was applied to." > > This sounds like an arbitrary new rule for just this functionality. I > don't think we should have special rules for a single static method call. > > I believe it's useful to have something like this, but I'm not in favour > of this approach. > > Would it not be possible for this to be a normal (dynamic) method on the > ReflectionAttrbute object? > > cheers > Derick > > > I agree that this is a bit odd, but the problem with just adding a dynami= c > method on the ReflectionAttribute object is that, in the attribute > constructor, there is no access to the ReflectionAttribute instance (unle= ss > you want to extract it from the backtrace, which we shouldn't suggest). > Internally, the implementation is doing that backtrace processing in a mo= re > stable way than userland probably would. > > We could adjust the signature, so that there is still a static method to > *get* the ReflectionAttribute, but then a normal dynamic method call on > that object to get the target reflection object: > > ``` > class ReflectionAttribute { > > // Call from the constructor of an attribute to get the original > ReflectionAttribute instance > public static function getCurrent(): ReflectionAttribute {} > > // After using getCurrent(), use this to get the reflection target > public function getReflectionTarget(): ReflectionAttributeTarget {} > } > ``` > > but either way I think we need some kind of (C-implemented) backtrace > processing, and because of that it makes sense to limit this to *just* > attribute constructors so that we don't need to process backtraces to an > arbitrary depth. > > An alternative would be to provide the reflection target (or the > ReflectionAttribute instance) to the attribute constructor as a parameter= , > but then we need some kind of way for attribute classes to signal that th= ey > want to be given that parameter, and then you get into the weeds on how t= o > opt-in (mark the parameter with a different attribute? add an interface, > even though constructors are exempt from signature checks?) that would > probably make that harder to reason with for end users. > > -Daniel > > > What about simply allowing an acceptance of the ReflectionAttribute in th= e > constructor? Engine-level injection, basically. You could have it > transparent from the attribute (kinda like self from python): > > #[Attribute] > class Att { > public function __construct(RelectionAttributeTarget $self, string $nam= e) {} > } > > > function thing(#[Att("name")] string $b) {} > > > It'd still be something "special" but attributes are already kinda specia= l > and magical. > > =E2=80=94 Rob > The problem with the lack of an explicit opt-in is that it would break existing attributes E.g. on 8.5, ReflectionAttribute::newInstance() for that example `Att` would be called with a single argument (the string), and on 8.6 it would be called with 2 arguments (the ReflectionAttributeTarget and the string) without the attribute author having, *or attribute user*, having changed anything. And you might think we could check based on parameter types, but then the attribute would be dropping support for older versions of PHP, whereas with a "magic" method the call could be conditional. Plus, just because a class *can* be used as an attribute, does not mean it *must always* be used as an attribute - and I found at least one case in symfony tests where they actually manually instantiate an attribute, https://github.com/symfony/symfony/blob/8e8f87c6fa5f47a431fc2f49bdbe601f676= 9e19d/src/Symfony/Component/JsonPath/Tests/Attribute/AsJsonPathFunctionTest= .php . Basically, if we provided the reflection information (whether it is a ReflectionAttribute or ReflectionAttributeTarget) via a parameter, we would run into one or more of the following * without any opt-in, breaking existing attributes by adding a new unexpected parameter * with an implicit opt-in of a typed parameter, breaking backwards compatibility for attributes supporting multiple versions of PHP * with an explicit opt-in of *this parameter should have the reflection information*, similar backwards compatibility breaks * confusion for library authors about how to use the new feature I agree that this is a bit weird as a calling pattern, but I've been trying to think of an alternative for months (I first started working on this at Longhorn PHP in October) and haven't been able to come up with anything cleaner. The only slight improvement I had thought of a few months ago was the addition of the instance method on ReflectionAttribute to get the reflection target, and then separately ::getCurrent() would return the ReflectionAttribute instance, but I think some "magic" method like this is still needed. -Daniel --00000000000047d32c0651050b82 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Mon, May 4, 2026 at 2:47=E2=80=AFPM Ro= b Landers <rob@bottled.codes> wrote:
=


On Mon, May 4, 2026, at 23:22, = Daniel Scherzer wrote:

On Mon, May 4, 2026 at 2:13=E2=80=AFPM Derick Rethans <derick@php.net> wrote:
On 4 May 2026 21:24:39 BST, Daniel Scherzer &= lt;daniel.= e.scherzer@gmail.com> wrote:
>Hi internals,
= >
>I'd like to start the discussion for a new RFC abo= ut adding a new method,
>ReflectionAttribute::getCurrent(), t= o access the current reflection target
>of an attribute.
>

=
"a new static method, ReflectionAttribute::getCurrent= (), that, when called from an attribute constructor, returns a reflection o= bject corresponding to what the attribute was applied to."
=
This sounds like an arbitrary new rule for just this functi= onality. I don't think we should have special rules for a single static= method call.

I believe it's useful to have = something like this, but I'm not in favour of this approach.
=
Would it not be possible for this to be a normal (dynamic)= method on the ReflectionAttrbute object?

cheers=
Derick

I agree that this = is a bit odd, but the problem with just adding a dynamic method on the Refl= ectionAttribute object is that, in the attribute constructor, there is no a= ccess to the ReflectionAttribute instance (unless you want to extract it fr= om the backtrace, which we shouldn't suggest). Internally, the implemen= tation is doing that backtrace processing in a more stable way than userlan= d probably would.

We could adjust the signature, s= o that there is still a static method to *get* the ReflectionAttribute, but= then a normal dynamic method call on that object to get the target reflect= ion object:

```
class ReflectionAttribut= e {

=C2=A0 =C2=A0 // Call from the constructor of = an attribute to get the original ReflectionAttribute instance
=C2= =A0 =C2=A0 public static function getCurrent(): ReflectionAttribute {}

=C2=A0 =C2=A0 // After using getCurrent(), use this to= get the reflection target
=C2=A0 =C2=A0 public function getRefle= ctionTarget():=C2=A0ReflectionAttributeTarget {}
}
```<= /div>

but either way I think we need some kind of (C-imp= lemented) backtrace processing, and because of that it makes sense to limit= this to *just* attribute constructors so that we don't need to process= backtraces to an arbitrary depth.

An alternative = would be to provide the reflection target (or the ReflectionAttribute insta= nce) to the attribute constructor as a parameter, but then we need some kin= d of way for attribute classes to signal that they want to be given that pa= rameter, and then you get into the weeds on how to opt-in (mark the paramet= er with a different attribute? add an interface, even though constructors a= re exempt from signature checks?) that would probably make that harder to r= eason with for end users.

-Daniel=C2=A0

What about simply allowing an accep= tance of the ReflectionAttribute in the constructor? Engine-level injection= , basically. You could have it transparent from the attribute (kinda like s= elf from python):

#[Attribute]
class Att {
  public function __construct(RelectionAttributeTarget $self, string $name)=
 {}
}

function thi=
ng(#[Att("name")] string $b) {}

It'd= still be something "special" but attributes are already kinda sp= ecial and magical.

=E2=80=94 Rob


The problem with the lack of an explicit opt-in is that it would b= reak existing attributes E.g. on 8.5, ReflectionAttribute::newInstance() fo= r that example `Att` would be called with a single argument (the string), a= nd on 8.6 it would be called with 2 arguments (the ReflectionAttributeTarge= t and the string) without the attribute author having, *or attribute user*,= having changed anything.

And you might think we c= ould check based on parameter types, but then the attribute would be droppi= ng support for older versions of PHP, whereas with a "magic" meth= od the call could be conditional.

Plus, just becau= se a class *can* be used as an attribute, does not mean it *must always* be= used as an attribute - and I found at least one case in symfony tests wher= e they actually manually instantiate an attribute,=C2=A0ht= tps://github.com/symfony/symfony/blob/8e8f87c6fa5f47a431fc2f49bdbe601f6769e= 19d/src/Symfony/Component/JsonPath/Tests/Attribute/AsJsonPathFunctionTest.p= hp.

Basically, if we provided the reflection i= nformation (whether it is a ReflectionAttribute or ReflectionAttributeTarge= t) via a parameter, we would run into one or more of the following

* without any opt-in, breaking existing attributes by addi= ng a new unexpected parameter
* with an implicit opt-in of a type= d parameter, breaking backwards compatibility for attributes supporting mul= tiple versions of PHP
* with an explicit opt-in of *this paramete= r should have the reflection information*, similar backwards compatibility = breaks
* confusion for library authors about how to use the new f= eature

I agree that this is a bit weird as a calli= ng pattern, but I've been trying to think of an alternative for months = (I first started working on this at Longhorn PHP in October) and haven'= t been able to come up with anything cleaner.

The = only slight improvement I had thought of a few months ago was the addition = of the instance method on ReflectionAttribute to get the reflection target,= and then separately ::getCurrent() would return the ReflectionAttribute in= stance, but I think some "magic" method like this is still needed= .

-Daniel=C2=A0
--00000000000047d32c0651050b82--