Hi internals,
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
- RFC: https://wiki.php.net/rfc/delayedtargetvalidation_attribute
- Implementation: https://github.com/php/php-src/pull/18817
--Daniel
Hi internals,
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
- RFC: https://wiki.php.net/rfc/delayedtargetvalidation_attribute
- Implementation: https://github.com/php/php-src/pull/18817
--Daniel
Interesting. I’d also argue for the inverse more than this, though. I’d like for my attributes to be validated during compilation instead of delayed to runtime -- which, it isn’t actually. Runtime validation ONLY happens when calling ->newInstance() on ReflectionAttribute, and never before then. So, only when an attribute is actually read during reflection is it validated. Further, if you never actually instantiate it ... it is never actually validated (i.e., just looking for the presence of an attribute, not the details).
— Rob
Von meinem iPhone gesendet
Am 18.06.2025 um 11:26 schrieb Rob Landers rob@bottled.codes:
Hi internals,
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
- RFC: https://wiki.php.net/rfc/delayedtargetvalidation_attribute
- Implementation: https://github.com/php/php-src/pull/18817
--Daniel
Interesting. I’d also argue for the inverse more than this, though. I’d like for my attributes to be validated during compilation instead of delayed to runtime -- which, it isn’t actually. Runtime validation ONLY happens when calling ->newInstance() on ReflectionAttribute, and never before then. So, only when an attribute is actually read during reflection is it validated. Further, if you never actually instantiate it ... it is never actually validated (i.e., just looking for the presence of an attribute, not the details).
As Daniel’s rfc mentions you need to differentiate between compiler and userland attributes.
The compiler attributes are validated at compile time not dueing newInstance.
— Rob
Von meinem iPhone gesendet
Am 18.06.2025 um 11:26 schrieb Rob Landers rob@bottled.codes:
Hi internals,
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
- RFC: https://wiki.php.net/rfc/delayedtargetvalidation_attribute
- Implementation: https://github.com/php/php-src/pull/18817
--Daniel
Interesting. I’d also argue for the inverse more than this, though. I’d like for my attributes to be validated during compilation instead of delayed to runtime -- which, it isn’t actually. Runtime validation ONLY happens when calling ->newInstance() on ReflectionAttribute, and never before then. So, only when an attribute is actually read during reflection is it validated. Further, if you never actually instantiate it ... it is never actually validated (i.e., just looking for the presence of an attribute, not the details).
As Daniel’s rfc mentions you need to differentiate between compiler and userland attributes.
The compiler attributes are validated at compile time not dueing newInstance.
— Rob
Just as an information:
We are at the moment in the proces of setting up a registry for userland attributes at the PHP-FIG.
For more information regarding that check out https://github.com/php-fig/fig-standards/pull/1331
Cheers
Andreas
--
Andreas Heigl
Von meinem iPhone gesendet
Am 18.06.2025 um 11:26 schrieb Rob Landers rob@bottled.codes:
Hi internals,
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
- RFC: https://wiki.php.net/rfc/delayedtargetvalidation_attribute
- Implementation: https://github.com/php/php-src/pull/18817
--Daniel
Interesting. I’d also argue for the inverse more than this, though. I’d like for my attributes to be validated during compilation instead of delayed to runtime -- which, it isn’t actually. Runtime validation ONLY happens when calling ->newInstance() on ReflectionAttribute, and never before then. So, only when an attribute is actually read during reflection is it validated. Further, if you never actually instantiate it ... it is never actually validated (i.e., just looking for the presence of an attribute, not the details).
As Daniel’s rfc mentions you need to differentiate between compiler and userland attributes.
The compiler attributes are validated at compile time not dueing newInstance.
— Rob
Yes, but when would it check it during runtime? It doesn't say in the RFC. From what I can tell, it effectively disables the attribute, unless someone happens to enumerate and instantiate all the attributes (which is unlikely).
— Rob
On Wed, Jun 18, 2025 at 1:28 AM Daniel Scherzer daniel.e.scherzer@gmail.com
wrote:
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
Hi Daniel,
While I'm in favor of the RFC, I'd more like to see the default behavior of
internal and userland attributes adjusted to work the same, with both
having delayed validation enabled by default. Treating core attributes
differently doesn't make sense to me.
So, if that's someone you're willing to work on, I'd very much prefer that.
But if there are downsides to this approach or if this is too
complicated for other reasons, this attribute is a net positive in my book
to make forward compatibility possible.
One note on the example code:
class Base {
class Child extends Parent {
\
Parent isn't a valid class name, and I think you wanted to extend from Base
here? I'd prefer the example to compile so that they can be used for
documentation later on where possible.
Kind Regards,
Volker
--
Volker Dusch
Head of Engineering
Tideways GmbH
Königswinterer Str. 116
53227 Bonn
https://tideways.io/imprint
Sitz der Gesellschaft: Bonn
Geschäftsführer: Benjamin Außenhofer (geb. Eberlei)
Registergericht: Amtsgericht Bonn, HRB 22127
On Wed, Jun 18, 2025 at 5:22 AM Volker Dusch volker@tideways-gmbh.com
wrote:
On Wed, Jun 18, 2025 at 1:28 AM Daniel Scherzer <
daniel.e.scherzer@gmail.com> wrote:I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.Hi Daniel,
One note on the example code:
class Base {
class Child extends Parent {
\Parent isn't a valid class name, and I think you wanted to extend from
Base here? I'd prefer the example to compile so that they can be used for
documentation later on where possible.Kind Regards,
Volker
Fixed, thanks.
Hi Volker
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.While I'm in favor of the RFC, I'd more like to see the default behavior of internal and userland attributes adjusted to work the same, with both having delayed validation enabled by default. Treating core attributes differently doesn't make sense to me.
So, if that's someone you're willing to work on, I'd very much prefer that.
I wouldn't support that, because internal attributes with effects are
not usually instantiated.
class C {
#[\SensitiveParameter] // This doesn't actually do anything, only
works on parameters
public $prop;
}
I would get no indication that this attribute doesn't behave as I
expect. We have at least a few attributes with confusable targets
(SensitiveParameter, Override, Deprecated, NoDiscard). User attributes
can't have effects without at least reading them through reflection,
although granted they don't necessarily need to be instantiated, and
so might also not trigger the error.
Ilija
Le mer. 18 juin 2025 à 23:49, Ilija Tovilo tovilo.ilija@gmail.com a
écrit :
Hi Volker
On Wed, Jun 18, 2025 at 2:23 PM Volker Dusch volker@tideways-gmbh.com
wrote:On Wed, Jun 18, 2025 at 1:28 AM Daniel Scherzer <
daniel.e.scherzer@gmail.com> wrote:I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.While I'm in favor of the RFC, I'd more like to see the default behavior
of internal and userland attributes adjusted to work the same, with both
having delayed validation enabled by default. Treating core attributes
differently doesn't make sense to me.So, if that's someone you're willing to work on, I'd very much prefer
that.
I 100% agree with what Volker posted here.
I wouldn't support that, because internal attributes with effects are
not usually instantiated.
class C {
#[\SensitiveParameter] // This doesn't actually do anything, only
works on parameters
public $prop;
}I would get no indication that this attribute doesn't behave as I
expect. We have at least a few attributes with confusable targets
(SensitiveParameter, Override, Deprecated, NoDiscard). User attributes
can't have effects without at least reading them through reflection,
although granted they don't necessarily need to be instantiated, and
so might also not trigger the error.
These considerations work exactly the same for userland attributes: if I
use #[Whatever] on a location that is not allowed by the declaration of the
attribute, nothing will ever tell me at runtime, because nobody will ever
try to read that attribute on that unexpected location.
Yet, this "silent" behavior is by design, because that's the core of the
"attributes are declarative metadata" promise. If you make them be enforced
by the engine, then this promise falls apart and attributes become way less
useful.
The correct solution to the validation problem is to use a static analyzer.
There, one can easily spot that some attributes are not correctly placed,
and one can then also ignore the report of the SA tool, because eg
#[Deprecated] is used on a class on purpose for that library (e.g. for the
forward compat use case).
The exception to the declarative nature of attributes that is currently
allowed for engine-provided ones is detrimental to me: it allows turning
them into "syntax hacks" basically (=engine-enforced-thus-not-declarative
rules).
To paraphrase Volker, I'm in favor of the RFC, but only if we cannot agree
on the need for internal and userland attributes to have the same
conceptual roots (truly declarative ones).
Cheers,
Nicolas
On Tue, Jun 17, 2025 at 4:26 PM Daniel Scherzer daniel.e.scherzer@gmail.com
wrote:
Hi internals,
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
- RFC: https://wiki.php.net/rfc/delayedtargetvalidation_attribute
- Implementation: https://github.com/php/php-src/pull/18817
--Daniel
It seems a common point of discussion is the difference in behavior between
internal and userland attributes, so I wanted to clarify a few things:
- Userland attributes are always metadata, in part because of the backwards
and forward compatibility that those attributes provide - the
attribute does not need to exist in order to be used, it just needs to
exist (and target the location) when you call
ReflectionAttribute::newInstance() to instantiate - Internal attributes are a mix between metadata and a way to plug into the
engine. There were already existing ways to plug into the engine (e.g.
using magic methods or implementing the Countable or ArrayAccess
interfaces) but attributes provided a way to plug into the engine when you
don't just want to add a function override, but rather something else (like
indicating a parameter should be redacted in backtraces with
#[\SensitiveParameter]
). It would probably be impossible to do that
securely with a userland attribute and userland error handler that manually
redacted things... - Attributes were designed to have good compatibility - the syntax chosen
for PHP 8.0 was, in prior versions of PHP, used for comments - so any code
with attributes could also work in PHP 7.4, just without the metadata.
Similarly, by not validating userland attributes until they are accessed
with reflection, you can add an attribute that does not exist yet (e.g. if
using different versions of a library) with minimal complications. - Internal attributes are validated at compile time - because they can be.
Internal attributes tell the engine to do something, and it makes sense (at
least to me) that if the engine cannot do that thing, there should be an
error without needing to wait for ReflectionAttribute::newInstance() to be
called.
But, the validation of internal attributes at compile time means that they
lose the compatibility features of userland attributes, and that is what
this RFC is trying to address. To be clear, I think the difference in
behavior between userland and internal attributes is a) fundamentally based
on the difference in capabilities (pure metadata vs engine behavior) and b)
something that should not be changed without significant further
investigation.
This new #[\DelayedTargetValidation]
is meant to simplify things, and to
partially unify the behavior of the errors - if you are getting any errors
from internal attributes and want to suppress them at compile time, just
add the new attribute everywhere.
-Daniel
Hi Daniel, internals,
On Wed, Jun 18, 2025, 02:29 Daniel Scherzer daniel.e.scherzer@gmail.com
wrote:
Hi internals,
I'd like to start the discussion for a new RFC about adding a
#[\DelayedTargetValidation]
attribute.
How about completely disabling errors caused by a bad target at compile
time?
And just ignore the attribute, that can be validated at runtime if needed.
IDEs and static code analysis would show the problem and that might be
enough.
--
Alex