On Tue, Jun 17, 2025 at 4:26 PM Daniel Scherzer <daniel.e.scher...@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

Reply via email to