Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130773 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 46E971A00BC for ; Tue, 5 May 2026 15:49:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1777996162; bh=eyogbVDl13/UhWkqV9xBuPa5jou8qbx4CJM2BXvA3Kk=; h=Date:From:To:In-Reply-To:References:Subject:From; b=Pl5cFLYoEKUZ/vnvDDlRpV8hPDjXzl43eVZMVfhkl7Cq/NtepERAfQ49MPcfBKuju KbFr7XSikT49/vMjozNAx7w6xGfxdhZd0IV279dw23P6nfbox4LfTuewQ3jpk3lZLO 6byU3fwMApfLPPa7EmFHDOYCSsJ3/TLz5DjreLYRhHdM2lwW9i5KJ0LUNclhVyBVGA h4suuCYMmNo2kZPE9342u00H8Z6uQan1AGWmPhMS5C3hCah3BV/l1iI080Dw7+ageQ xSU1IoKfqvuvHa/NaKYNqd3n0Nas4kz9U1+Pbdq+3bU4xIjcpRlyItM2TnDMVzzOEX UY44S/zZMsssg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D30231801D7 for ; Tue, 5 May 2026 15:49:20 +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.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,RCVD_IN_DNSWL_LOW, SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-a2-smtp.messagingengine.com (fhigh-a2-smtp.messagingengine.com [103.168.172.153]) (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 ; Tue, 5 May 2026 15:49:20 +0000 (UTC) Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfhigh.phl.internal (Postfix) with ESMTP id F3639140008B for ; Tue, 5 May 2026 11:49:14 -0400 (EDT) Received: from phl-imap-02 ([10.202.2.81]) by phl-compute-04.internal (MEProxy); Tue, 05 May 2026 11:49:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to; s=fm3; t=1777996154; x=1778082554; bh=uiIbhCM9DRuwAydWuVn8Z 1gTC2URRNYyKVGqcin2VcI=; b=zX22kPNizeyFDvTdgQ3VWSGhSwenH6FC9cqBd NgqXYIJTevCg1veaYyKrk1+7hRUDdT25xJLrn7JN7EefwlpgSBV2Ir4M9aQijv+l kvyqVzkNPKSVzLFHAHC7qD90cMpHS3DDP06KKdJEPPGpwSL6An3ZSmzGacnVOHgz bXQxRJQ6cc4SzjqCwx9F8Jwwy/iSWRR5GGfuwn26TpvuKTh5P3TaIJSNJhKUT7l2 MjvCeY48zzqiRtgXgQk0NjQoLP0FlMh66UB+HS2Jg76guJDV9Eh9HCR5yVl4F2BR ewUZhDp+7h562cRfFu+iwjgfJAlXfDUXUV5yBTlGzPoQBmEXg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1777996154; x=1778082554; bh=u iIbhCM9DRuwAydWuVn8Z1gTC2URRNYyKVGqcin2VcI=; b=glrnrA8ZjwofDtMGU YXvMRQPp3Nus5J29G2ZPieLETsskkSXFZSA/zkAO/WaDIZFMVqmf265uC0kcPeCv VahLYOHkdReu6NFi+dPQKXpLZG0sRXrZ6Ir9+uTBZNzJGHAZrcKOmN7RdvMsjk1i Y750zU/c3bC+WPL7zEaV6Bqs6OAYzwEtE+TmnrIjVn0GTUdQ2E02h57lhdlzDJzz Riz29bZsJLCCacBQ/TXAdT5OsmLsIKY7T+KKteUroqUJ5R/G0GhcrPw/diPtZiQW 96g8zAC3mbfet4SRvnWGfs/0PbH1dD6pDyuarfIJndaFphqXdc0vDbRfMOEoRKY1 nUBvQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgddutddvudduucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepofggfffhvffkjghfufgtgfesthhqredtredtjeenucfhrhhomhepfdfnrghrrhih ucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhmqe enucggtffrrghtthgvrhhnpedugffhgfduffefvdejvedthfduffeiteefhfdtkedvjefg gedvleeihfdtfefhheenucffohhmrghinhepphhhphdrnhgvthdpghhithhhuhgsrdgtoh hmpdgvgihtvghrnhgrlhhsrdhiohenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr mhepmhgrihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomhdpnh gspghrtghpthhtohepuddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepihhnthgv rhhnrghlsheslhhishhtshdrphhhphdrnhgvth X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 745AE700065; Tue, 5 May 2026 11:49:14 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: A2BiHuuqJSJg Date: Tue, 05 May 2026 10:48:54 -0500 To: "php internals" Message-ID: In-Reply-To: References: Subject: Re: [PHP-DEV] [RFC] [Discussion] Add ReflectionAttribute::getCurrent() Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable From: larry@garfieldtech.com ("Larry Garfield") On Mon, May 4, 2026, at 4:58 PM, Daniel Scherzer wrote: > On Mon, May 4, 2026 at 2:47=E2=80=AFPM Rob Landers = wrote: >> __ >>=20 >>=20 >> On Mon, May 4, 2026, at 23:22, Daniel Scherzer wrote: >>>=20 >>> On Mon, May 4, 2026 at 2:13=E2=80=AFPM Derick Rethans wrote: >>>> 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 reflectio= n target >>>> >of an attribute. >>>> > >>>> >* RFC: https://wiki.php.net/rfc/reflectionattribute-getcurrent >>>>=20 >>>>=20 >>>> "a new static method, ReflectionAttribute::getCurrent(), that, when= called from an attribute constructor, returns a reflection object corre= sponding to what the attribute was applied to." >>>>=20 >>>> 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 c= all. >>>>=20 >>>> I believe it's useful to have something like this, but I'm not in f= avour of this approach. >>>>=20 >>>> Would it not be possible for this to be a normal (dynamic) method o= n the ReflectionAttrbute object? >>>>=20 >>>> cheers >>>> Derick >>>=20 >>> I agree that this is a bit odd, but the problem with just adding a d= ynamic method on the ReflectionAttribute object is that, in the attribut= e constructor, there is no access to the ReflectionAttribute instance (u= nless you want to extract it from the backtrace, which we shouldn't sugg= est). Internally, the implementation is doing that backtrace processing = in a more stable way than userland probably would. >>>=20 >>> We could adjust the signature, so that there is still a static metho= d to *get* the ReflectionAttribute, but then a normal dynamic method cal= l on that object to get the target reflection object: >>>=20 >>> ``` >>> class ReflectionAttribute { >>>=20 >>> // Call from the constructor of an attribute to get the original= ReflectionAttribute instance >>> public static function getCurrent(): ReflectionAttribute {} >>>=20 >>> // After using getCurrent(), use this to get the reflection targ= et >>> public function getReflectionTarget(): ReflectionAttributeTarget= {} >>> } >>> ``` >>>=20 >>> but either way I think we need some kind of (C-implemented) backtrac= e 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 a= n arbitrary depth. >>>=20 >>> An alternative would be to provide the reflection target (or the Ref= lectionAttribute instance) to the attribute constructor as a parameter, = but then we need some kind of way for attribute classes to signal that t= hey want to be given that parameter, and then you get into the weeds on = how to opt-in (mark the parameter with a different attribute? add an int= erface, even though constructors are exempt from signature checks?) that= would probably make that harder to reason with for end users. >>>=20 >>> -Daniel=20 >>=20 >> What about simply allowing an acceptance of the ReflectionAttribute i= n the constructor? Engine-level injection, basically. You could have it = transparent from the attribute (kinda like self from python): >>=20 >> #[Attribute] >> class Att { >> public function __construct(RelectionAttributeTarget $self, string = $name) {} >> } >>=20 >> function thing(#[Att("name")] string $b) {} >>=20 >> It'd still be something "special" but attributes are already kinda sp= ecial and magical. >>=20 >> =E2=80=94 Rob > > > The problem with the lack of an explicit opt-in is that it would break=20 > existing attributes E.g. on 8.5, ReflectionAttribute::newInstance() fo= r=20 > that example `Att` would be called with a single argument (the string)= ,=20 > and on 8.6 it would be called with 2 arguments (the=20 > ReflectionAttributeTarget and the string) without the attribute author=20 > having, *or attribute user*, having changed anything. > > And you might think we could check based on parameter types, but then=20 > the attribute would be dropping support for older versions of PHP,=20 > whereas with a "magic" method the call could be conditional. > > Plus, just because a class *can* be used as an attribute, does not mea= n=20 > it *must always* be used as an attribute - and I found at least one=20 > case in symfony tests where they actually manually instantiate an=20 > attribute,=20 > https://github.com/symfony/symfony/blob/8e8f87c6fa5f47a431fc2f49bdbe60= 1f6769e19d/src/Symfony/Component/JsonPath/Tests/Attribute/AsJsonPathFunc= tionTest.php. > > Basically, if we provided the reflection information (whether it is a=20 > ReflectionAttribute or ReflectionAttributeTarget) via a parameter, we=20 > would run into one or more of the following > > * without any opt-in, breaking existing attributes by adding a new=20 > unexpected parameter > * with an implicit opt-in of a typed parameter, breaking backwards=20 > compatibility for attributes supporting multiple versions of PHP > * with an explicit opt-in of *this parameter should have the reflectio= n=20 > 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=20 > trying to think of an alternative for months (I first started working=20 > on this at Longhorn PHP in October) and haven't been able to come up=20 > with anything cleaner. > > The only slight improvement I had thought of a few months ago was the=20 > addition of the instance method on ReflectionAttribute to get the=20 > reflection target, and then separately ::getCurrent() would return the=20 > ReflectionAttribute instance, but I think some "magic" method like thi= s=20 > is still needed. > > -Daniel For context, there was a discussion last year about this problem space: https://externals.io/message/127853 The issue is that there's really no good, clean solution to giving an at= tribute access to the reflection target it is on. All options have some= significant drawback. (See that thread for details.) I don't like it either, but this approach is the least-bad I can think o= f. If someone has a better alternative with fewer trade-offs, do share. I believe this would let me greatly simplify AttributeUtils, in practice. (Disclosure: Daniel and I discussed this issue at length back at Longhor= n PHP, along with a few others.) --Larry Garfield