Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127866 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 70FB41A00BC for ; Thu, 3 Jul 2025 17:16:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1751562849; bh=XZE0Ko6/Xmd7wDM7T2Ex08QRKbtIkqlR2i1gpm9M4tU=; h=From:Subject:Date:References:Cc:In-Reply-To:To:From; b=ez6i123HF8hmRXsqBEuWuYnylM00Km/eBrnVs2zbJUTCwehogtUbFeCIRPgkt0GIA P+0f6FPfebrMfSoGZK9sndDFAkf8l5D+B0MGnMCQgRCrERVaMi0VFz5xufeBBfMwro SBI4OiIlHhatEWAi5VpbBDUNqApnZ0159NIn2fil4ywuMLzyt3d1NmnFo0VIhF1m0W f/DU30NdCJNl1oPI3UeQCM00tnyF/bplm+U8xl/BOhJTwkYVFgvKT8HpYZxDJiLzQy 9g4kbV9kciMtzGoAEBYiXV9uaTV9KD74JIPbvPv0dLOQnZ0iCCLB9LfyecXV0u5tOs n1WzGiPjADqpA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 50B091801E0 for ; Thu, 3 Jul 2025 17:14:08 +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=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,MIME_QP_LONG_LINE, SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail1.25mail.st (mail1.25mail.st [206.123.115.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 3 Jul 2025 17:14:08 +0000 (UTC) Received: from smtpclient.apple (unknown [49.48.241.21]) by mail1.25mail.st (Postfix) with ESMTPSA id 4F2706070F; Thu, 3 Jul 2025 17:15:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=koalephant.com; s=25mailst; t=1751562959; bh=XZE0Ko6/Xmd7wDM7T2Ex08QRKbtIkqlR2i1gpm9M4tU=; h=From:Subject:Date:References:Cc:In-Reply-To:To:From; b=fmrbvxZglnRMxME6Ezpyxgb1JPKQkYvS7YAxmTcxV9coUfCY60ooGsdZVEuTY5GGk C8QmMQkMeCI2tt/lwOZhqwgl7KJMsB41sQTVuCX3ZtGkq17umMvPiMY5tm8ZkqNi/R kYNR1Wnbtmmmwljwb0fLiyzouHOhX+zG7uYH9mplPcJrMYPekcsN9DQkHKDT0fcvSa mKn6nTJTlY1Efak/Ymwx2H185AwjhW4UpJV2a4lLCLXFgxgibwuVSNc0g59LD1fLEA dPaEgdRvokz34+coFM54IVikvnB2ELVnMjTbVy/RVN5SkRVRWRHFKZmCpryKCpnebP DReOFGvUZIiHw== Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow Mime-Version: 1.0 (1.0) Subject: Re: [PHP-DEV] [RFC idea] Target-aware attributes Date: Fri, 4 Jul 2025 00:15:42 +0700 Message-ID: <20DACB49-3C84-4B23-98E2-35050D9EDAC9@koalephant.com> References: <1cfc477a-781f-40e9-9e37-dd748ef261be@app.fastmail.com> Cc: php internals In-Reply-To: <1cfc477a-781f-40e9-9e37-dd748ef261be@app.fastmail.com> To: Larry Garfield X-Mailer: iPhone Mail (22F76) From: php-lists@koalephant.com (Stephen Reay) Sent from my iPhone > On 3 Jul 2025, at 23:40, Larry Garfield wrote: >=20 > =EF=BB=BFOn Wed, Jul 2, 2025, at 5:26 PM, Andreas Hennings wrote: >> This topic was discussed in the past as "Declaration-aware >> attributes", and mentioned in the discussion to "Amendments to >> Attributes". >> I now want to propose a close-to-RFC iteration of this. >> (I don't have RFC Karma, my wiki account is "Andreas Hennings (donquixote= )") >>=20 >> ----- >>=20 >> Primary proposal >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>=20 >> I propose to introduce 3 new methods on ReflectionAttribute. >>=20 >> static ReflectionAttribute::getCurrentTargetReflector(): ?Reflector >> Most of the time, this will return NULL. >> During the execution of ReflectionAttribute->newInstance(), it will >> return the reflector of the symbol on which the attribute is found. >> (in other words, during >> $reflector->getAttributes()[$i]->newInstance(), it will return >> $reflector.) >> During the execution of >> ReflectionAttribute::invokeWithTargetAttribute($target, $callback), it >> will return $target. >> If the call stack contains multiple calls to the above mentioned >> methods, only the closest/deepest one counts. >> (This means that php needs to maintain a stack of reflectors.) >=20 > *snip* >=20 >> Other alternatives >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>=20 >> In older discussions, it was suggested to provide the target reflector >> as a special constructor parameter. >> This is problematic because an attribute expression #[MyAttribute('a', >> 'b', 'c')] expects to pass values to all the parameters. >>=20 >> Another idea was to provide the target reflector through a kind of >> setter method on the attribute class. >> This can work, but it makes attribute classes harder to write, because >> the constructor does not have all the information. >> It may also prevent attribute classes from being stateless (depending >> how we define stateless). >>=20 >>=20 >> Userland implementations >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= >>=20 >> One userland implementation that was mentioned in this list in the >> past is in the 'crell/attributeutils' package. >> This one uses a kind of setter injection for the target reflector. >> See >> https://github.com/Crell/AttributeUtils/blob/master/src/FromReflectionCla= ss.php >=20 > Hey, I know that guy! :-) >=20 >> Another userland implementation is in the >> 'ock/reflector-aware-attributes' package. >> https://github.com/ock-php/reflector-aware-attributes (I created that one= ) >> This supports both a setter method and getting the target reflector >> from the attribute constructor. >>=20 >> The problem with any userland implementation is that it only works if >> the attribute is instantiated (or processed) using that userland >> library. >> Simply calling $reflector->getAttributes()[0]->newInstance() would >> either return an instance that is incomplete, or it would break, if >> the attribute class expects access to its target. >=20 > I am unsurprisingly in favor of finding a solution here, as there are innu= merable cases where you need the reflectable that the attribute is on; the m= ost common for me is using the name/type of a property as defaults for the a= ttribute. >=20 > However, I am very skeptical about a stateful global value as the solution= . We've tried very hard to remove those from PHP, mostly successfully. Add= ing another one back in feels like a major step backwards, and a great place= for weird bugs to hide. >=20 > A setter method injection is what I did in AttributeUtils, because it was t= he only real option. Alternatively, I suppose core could use property sette= r injection (either a magically named property like $__reflector, or a prope= rty that itself has an attribute on it, etc.). That would allow it to be se= t before the constructor is called, and with property hooks would allow proc= essing 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 t= he property, use it, and then remember to unset it at some point. That's cl= umsy. >=20 > --Larry Garfield >=20 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 a= ccepts a single Reflector argument. If the attribute implements the interface, the method is called immediately f= ollowing instantiation.=20 Yes this means logic dependant on the reflector has to be delayed until the m= ethod is called. I think this is an acceptable payoff for the solution: it o= nly applies to attributes that explicitly opt in to receive the Reflector, a= nd it helps to not encourage storing the reflector in a property. In theory I guess it could call a static named constructor, but the other ar= guments would have to be an array, which would end up being quite clunky if t= he goal is to derive default argument values from the reflector. I'm really looking forward to this feature, thanks for introducing this disc= ussion/RFC! Cheers Stephen=20