Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127868 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 14BC11A00BC for ; Thu, 3 Jul 2025 17:55:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1751565199; bh=vGt8A/yrNyRS7aZUBHoiRWc4IHU3fbJAQGTiJb9xBow=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=enBOpl5ni7yX5EHDkaUnnTqp6+5i+n9GQPbDJJF1Z4Mkm4EymNBhueUbkdkDDcaw9 aYzuPwGpqVb52y7nqCKCD965wXzKl48xNfxe9GRqXlA2iwkedEfIls9IIhkLV+eoTx S6PEB1zDDq0rTfacP2+/oe/V48n94X2lQDcHSFd/uOhSecKUEHb25yRoY3NK/tntLN lYoA9H5ix9Dk3Hrwu9CIcPF6ZpU4a/gteXFWkmlIsrvwoacyJluABf0ttsvacdGn2P KDA0ElfQpfOvjd8PiLER7wczXS6qD7BbCvGbH/LJVWdh7UC+W0QUniynC4djvoMAPX /2kf3joEzn7yg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CF9521805F3 for ; Thu, 3 Jul 2025 17:53:18 +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=-1.2 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,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: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-yw1-f169.google.com (mail-yw1-f169.google.com [209.85.128.169]) (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 ; Thu, 3 Jul 2025 17:53:18 +0000 (UTC) Received: by mail-yw1-f169.google.com with SMTP id 00721157ae682-70e5d953c0bso822437b3.1 for ; Thu, 03 Jul 2025 10:55:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dqxtech.net; s=google; t=1751565310; x=1752170110; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=2jJEw8uHmw0HAj1Pa+bmJUQB9Y1YbOAxKxLSJcVyvoQ=; b=J5omZ1SkCroKZOBgCdcJKkQIHOlSpibeZt4p0xKguMM8TfpDlaM4kfHBq0UWRIho+W kEj7RXt3DLH8CiZy3W6djnGPDa8K//hBAWtUTjnrVrYMS40xgAlcQwouHNIXMtu3Sc9G +W1Itdah2RtFQCxRCPX5W7hlsmY5oD897JhbGwRpnVsiJ/ev/PMWkDQAYsNlfZHhriSK 6qUXoFXqwOQDxdt1vTXJ/hwnTT8wjIQLdAgwJeGSkj+nytDGWU3xX3o6uxGrqcwH3EaC Zw7uybdBoAuSHW1kwLJxap23GRu8KpxH3kUu/lvsKdE2TxfQjsQ6QmJWx5chbWdCC0lY pteA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751565310; x=1752170110; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2jJEw8uHmw0HAj1Pa+bmJUQB9Y1YbOAxKxLSJcVyvoQ=; b=FP0Rc484fIjVHGYTldm6QY1i5FhWIOYM5OPjV/bm0REXZqikAVRfHgY3pMQ2Ky/HKm F5FK22fh3IH8gFeZIiC7s8ock3pyG64uoDXFXNql+PNEMRuREaCS+ehYYbJOrhsipgQ+ s6MYsoRHP5h7Z5xtw8js58n0SlE+ok5zqcFcgN0OGc5jYm8zYURU8noMtM5ZfEb03KpD WurwkdPQEbjx7eJNjhTbxoCjsDCDq3VV6WVl6c9xjkTD5H8uPAMH6YxMYmQWUPMb6Laa aZd7CNyyqI0LFywJZ0VxVWM0K86iFmZwppJUAdmCJNCpthvPZoUYc43XZ9SEg0dHWz24 mmeA== X-Forwarded-Encrypted: i=1; AJvYcCXXSg3lOH2UIkNk9lsgr6YfUYDJRO2zQ/DdUTRrwWUch5K99jN233foPn4SSyuZHNLT2BzjISai3+Y=@lists.php.net X-Gm-Message-State: AOJu0YwECH9Ppk9NPbE5xu7+IyiDD9ff93v26WVLzMiVVmEdU40Iq2X7 vds+qFjuri/+idjDAwZV+DMNpT4GPd4itaoQcWNsPOJkQiYhUtpEO6Km03W+tQw40Z+68bcxtSu euafK9e2xExYija/gUlhXz6tBRv7MWSn8JwT0CLHeyA== X-Gm-Gg: ASbGncutnNIpdZLRAL5bJABZFru870TPUljogz+XxPltcIzjD6gSuMLxwm2mSU/Ha4l VABJ3BAUxa8MQgnOeqgIYKJHpUgy98HOm1y/fF0zbx1sGoDVMOsj+lumM5s4VsTWryPbV78mr6b YVIF+/eYhhTPZwo81AxjQl4t0i5NmyaCofvvpfKEE16Lq07fLywpCTCSUo1oM7w4SFtGXBDPOae T4T X-Google-Smtp-Source: AGHT+IGz7bnSkTBECPGTCuwu/kqFoHQIgfYK/4QDW0QeP2z/WszlpquhCPY0p+ARzfFNFt05pFnhkeQ9RKUufbXJbpc= X-Received: by 2002:a05:690c:60c3:b0:70f:751c:2d8a with SMTP id 00721157ae682-71658fbc2f8mr61845077b3.3.1751565310073; Thu, 03 Jul 2025 10:55:10 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <1cfc477a-781f-40e9-9e37-dd748ef261be@app.fastmail.com> <20DACB49-3C84-4B23-98E2-35050D9EDAC9@koalephant.com> In-Reply-To: <20DACB49-3C84-4B23-98E2-35050D9EDAC9@koalephant.com> Date: Thu, 3 Jul 2025 19:54:56 +0200 X-Gm-Features: Ac12FXzluKenNNF2rfsVgPSatefQDD9JmcS1y9D0hgIKbJTMRlq3jYoBHjYeCGU Message-ID: Subject: Re: [PHP-DEV] [RFC idea] Target-aware attributes To: Stephen Reay Cc: Larry Garfield , php internals Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: andreas@dqxtech.net (Andreas Hennings) On Thu, 3 Jul 2025 at 19:17, Stephen Reay wrote: > > > > > Sent from my iPhone > > On 3 Jul 2025, at 23:40, Larry Garfield wrote: > > > > =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 (donquix= ote)") > >> > >> ----- > >> > >> Primary proposal > >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > >> > >> I propose to introduce 3 new methods on ReflectionAttribute. > >> > >> 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.) > > > > *snip* > > > >> Other alternatives > >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > >> > >> 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. > >> > >> 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). > >> > >> > >> 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 > >> > >> 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/FromReflection= Class.php > > > > Hey, I know that guy! :-) > > > >> 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. > >> > >> 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. > > > > I am unsurprisingly in favor of finding a solution here, as there are i= nnumerable cases where you need the reflectable that the attribute is on; t= he most common for me is using the name/type of a property as defaults for = the attribute. > > > > However, I am very skeptical about a stateful global value as the solut= ion. We've tried very hard to remove those from PHP, mostly successfully. = Adding another one back in feels like a major step backwards, and a great = place for weird bugs to hide. > > > > A setter method injection is what I did in AttributeUtils, because it w= as 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 t= o be set before the constructor is called, and with property hooks would al= low processing either immediately or later in the constructor. The downsid= e here is that Attribute are, generally, serializable, but a Reflection obj= ect 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 proble= m, I have an alternative solution, based somewhat on an internalised conce= pt of "never store Reflectors". > > Introduce an interface "ReflectorAttribute" (bike shedding to come); whic= h accepts a single Reflector argument. > > If the attribute implements the interface, the method is called immediate= ly 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 this means logic dependant on the reflector has to be delayed until t= he method is called. I think this is an acceptable payoff for the solution:= it only applies to attributes that explicitly opt in to receive the Reflec= tor, and it helps to not encourage storing the reflector in a property. yep, same tradeoff I mentioned in the other mail. > > In theory I guess it could call a static named constructor, but the other= arguments would have to be an array, which would end up being quite clunky= if the goal is to derive default argument values from the reflector. > > I'm really looking forward to this feature, thanks for introducing this d= iscussion/RFC! > > > > Cheers > > Stephen