Re: [PHP-DEV] #[Deprecated] Attribute

On Jan 13, 2021, at 06:43, Benjamin Eberlei <kontakt@beberlei.de> wrote:

On Wed, Jan 13, 2021 at 1:05 PM Brent Roose <brendt@stitcher.io> wrote:

Hi Sara

On 22 Dec 2020, at 19:54, Sara Golemon <pollita@php.net> wrote:

On Tue, Dec 22, 2020 at 12:35 PM Nicolas Grekas <
nicolas.grekas+php@gmail.com> wrote:

It would be great to allow adding this attribute on classes. What about
allowing it right now and not bind it to any runtime side-effect? That
would allow static analyzers to do their job. Same for consts and
properties by the way.

Also, it would be very useful to add named parameters to the attribute,
namely: "package" (the name of the package that declares the deprecation)
and "version" (the version of that package that introduced the
deprecation), next to the message.

This is critical info when building reports of deprecations.

You could do that now with a polyfill from userspace. If the annotation
need not have an effect, then it's just any other userspace implementation.

The difference is that PHP core has the ability to force standarization.
There's already JetBrains' implementation of #[Deprecated], which Psalm and
PhpStan also support, but it's not a real standard. Maybe the FIG would one
day step in to decide these kinds of things, but the reality is that many
major frameworks don't follow FIG as closely as they used to. I think
there's value in adding attributes in the core, with the goal only being
static analysis. It'll allow for consistency and that's a valuable thing.

I want to keep #[Deprecated] on other elements than functions / methods out
of this RFC, because they require entirely different implementation
approaches.

We identified in the PR already that this should at some point be
standardized in core, because internal attributes will currently not be
able to support extension through inheritance by userland for
implementation reasons.

My next RFC update will reflect this future scope.

Last night, I identified a need for `#[Deprecated]` on a userland class in one of my libraries, but I had to settle on `@deprecated` for the widest range of compatibility.

Has there been anymore thought on putting together an implementation for this? I’m happy to draft an RFC if someone is able to help with the implementation. I don’t understand the complexities around the implementation, but is this something that could make it into 8.5, provided an RFC vote passes?

Cheers,
Ben

On Tue, May 27, 2025 at 9:41 PM Ben Ramsey <ramsey@php.net> wrote:

Last night, I identified a need for #[Deprecated] on a userland class in one of my libraries, but I had to settle on @deprecated for the widest range of compatibility.

Has there been anymore thought on putting together an implementation for this? I’m happy to draft an RFC if someone is able to help with the implementation. I don’t understand the complexities around the implementation, but is this something that could make it into 8.5, provided an RFC vote passes?

Cheers,
Ben

I’d be willing to work on the implementation, but what I’m wondering is what exactly it would mean to deprecate a class. Without a clear idea of the goal, I didn’t include this in https://news-web.php.net/php.internals/127305 even though I had considered it. Would a deprecated class

  • Emit warnings when constructed? Just deprecate the constructor, https://3v4l.org/DNrqm
  • Emit warnings when used as a type? But we allow types to include classes that don’t exist (https://3v4l.org/pdkbv) so needing to look up the types that are declared to emit warnings (rather than just when used to verify that the type is respected) would presumably have a performance impact.
  • Emit warnings when extended? I suggested that in my email a few weeks ago, and when I have time I was going to look into that - I was thinking something like #[\WillBeFinal] that would work for classes, methods, properties, and constants, and would emit warnings just like #[\Deprecated] but not when a method is called or a constant is used, just when things are overridden

What were you thinking in terms of desired semantics?

–Daniel

Am 28.05.2025, 06:54:22 schrieb Daniel Scherzer <daniel.e.scherzer@gmail.com>:

On Tue, May 27, 2025 at 9:41 PM Ben Ramsey <ramsey@php.net> wrote:

Last night, I identified a need for #[Deprecated] on a userland class in one of my libraries, but I had to settle on @deprecated for the widest range of compatibility.

Has there been anymore thought on putting together an implementation for this? I’m happy to draft an RFC if someone is able to help with the implementation. I don’t understand the complexities around the implementation, but is this something that could make it into 8.5, provided an RFC vote passes?

Cheers,
Ben

I’d be willing to work on the implementation, but what I’m wondering is what exactly it would mean to deprecate a class. Without a clear idea of the goal, I didn’t include this in https://news-web.php.net/php.internals/127305 even though I had considered it. Would a deprecated class

  • Emit warnings when constructed? Just deprecate the constructor, https://3v4l.org/DNrqm
  • Emit warnings when used as a type? But we allow types to include classes that don’t exist (https://3v4l.org/pdkbv) so needing to look up the types that are declared to emit warnings (rather than just when used to verify that the type is respected) would presumably have a performance impact.
  • Emit warnings when extended? I suggested that in my email a few weeks ago, and when I have time I was going to look into that - I was thinking something like #[\WillBeFinal] that would work for classes, methods, properties, and constants, and would emit warnings just like #[\Deprecated] but not when a method is called or a constant is used, just when things are overridden

What were you thinking in terms of desired semantics?

—Daniel

Hi Daniel, Hi Ben,

Tim and I ideated on this topic before, but we haven’t gotten further yet. I wanted to share my notes though, so that you have them as one idea. Its not more than a brain dump though:

  • Deprecated classes
  • mark the following elements deprecated:
  • constructor method (what if it doesnt have one?)
  • public static methods
  • public static properties
  • public constants- not public properties or methods, because the message is already generated on new DeprecatedClass
  • during generating the message see if its classed based and slightly change message to indicate its a class based deprecation

On Tue, 27 May 2025 at 20:05, Ben Ramsey <ramsey@php.net> wrote:

On Jan 13, 2021, at 06:43, Benjamin Eberlei <kontakt@beberlei.de> wrote:

On Wed, Jan 13, 2021 at 1:05 PM Brent Roose <brendt@stitcher.io> wrote:

Hi Sara

On 22 Dec 2020, at 19:54, Sara Golemon <pollita@php.net> wrote:

On Tue, Dec 22, 2020 at 12:35 PM Nicolas Grekas <
nicolas.grekas+php@gmail.com> wrote:

It would be great to allow adding this attribute on classes. What about
allowing it right now and not bind it to any runtime side-effect? That
would allow static analyzers to do their job. Same for consts and
properties by the way.

Also, it would be very useful to add named parameters to the attribute,
namely: “package” (the name of the package that declares the deprecation)
and “version” (the version of that package that introduced the
deprecation), next to the message.

This is critical info when building reports of deprecations.

You could do that now with a polyfill from userspace. If the annotation
need not have an effect, then it’s just any other userspace implementation.

The difference is that PHP core has the ability to force standarization.
There’s already JetBrains’ implementation of #[Deprecated], which Psalm and
PhpStan also support, but it’s not a real standard. Maybe the FIG would one
day step in to decide these kinds of things, but the reality is that many
major frameworks don’t follow FIG as closely as they used to. I think
there’s value in adding attributes in the core, with the goal only being
static analysis. It’ll allow for consistency and that’s a valuable thing.

I want to keep #[Deprecated] on other elements than functions / methods out
of this RFC, because they require entirely different implementation
approaches.

We identified in the PR already that this should at some point be
standardized in core, because internal attributes will currently not be
able to support extension through inheritance by userland for
implementation reasons.

My next RFC update will reflect this future scope.

Last night, I identified a need for #[Deprecated] on a userland class in one of my libraries, but I had to settle on @deprecated for the widest range of compatibility.

Has there been anymore thought on putting together an implementation for this? I’m happy to draft an RFC if someone is able to help with the implementation. I don’t understand the complexities around the implementation, but is this something that could make it into 8.5, provided an RFC vote passes?

Cheers,
Ben

I have needed this as well at work for a shared library and i’m sure many library authors would use it too.
Current IDE’s like jetbrains has support for #[Deprecated($reason, $replacement)] which will throw warning in the IDE,
see their implementation here: https://github.com/JetBrains/phpstorm-attributes?tab=readme-ov-file#deprecated

If this could be supported at a language level, package authors, frameworks and internal company libraries would benefit from it.
I see no reason why anyone would be against the idea, other than pure chaos evil.

On 6/1/25 17:31, fennic log wrote:

I have needed this as well at work for a shared library and i'm sure many
library authors would use it too.
Current IDE's like jetbrains has support for #[Deprecated($reason,
$replacement)] which will throw warning in the IDE,
see their implementation here:
GitHub - JetBrains/phpstorm-attributes: PhpStorm specific attributes

If this could be supported at a language level, package authors, frameworks
and internal company libraries would benefit from it.
I see no reason why anyone would be against the idea, other than pure chaos
evil.

I don't think the issue is that anyone is against the idea. I think the issue is that it's unclear what the behavior should be.

Following from Benjamin Außenhofer's post:

- Deprecated classes
  - mark the following elements deprecated:
    - constructor method (what if it doesnt have one?)
    - public static methods
    - public static properties
    - public constants
  - not public properties or methods, because the message is already
    generated on new DeprecatedClass
  - during generating the message see if its classed based and
    slightly change message to indicate its a class based deprecation

I hadn't gotten very far along in thinking about it. What led me to resurrect this old thread was this:

I wanted to mark a class a deprecated because I'll be removing it in the next major version of ramsey/uuid. When anyone tries to "use" the class, I'd like them to see a deprecation message.

"Use" is doing a lot of heavy-lifting here.

When I annotate the class with `@deprecated`, that helps in several ways:

* JetBrains IDEs show the class name with a strike-through line
* PHPStan and Psalm complain about its use
* PHP_CodeSniffer can be configured to complain about it
* Other tooling I might not be aware of does stuff

The goal is to make sure users are aware of the deprecation.

If we don't change to the language to support `#[\Deprecated]` at the class level, what is the common practice library authors should follow that will allow all the tooling (and PHP's deprecation messages) to make users aware?

* Add the attribute to the constructor?
* Add it to all public static properties, methods, constants?

If all the tooling will appropriately warn the user when the attribute is on the constructor, then I don't think there's a need to make a change to the language.

I guess I'll need to do a little investigation now to see how all the tools respond when using the attribute on various elements.

Cheers,
Ben