PHP 8.4: #[Deprecated] attribute

Version8.4
TypeNew Feature

PHP 8.4 introduces a new PHP Attribute named #[Deprecated], that can attribute a PHP function, a class method, or a class constant as deprecated.

When using a deprecated function, class, or a method with the #[Deprecated] attribute, PHP automatically emits a deprecation message. This happens for each time the function/method/constant is used.

Prior to the introduction of this attribute, the typical way of announcing deprecations of user-land PHP functions/methods/constants is by emitting a deprecation message using the trigger_error function, and/or by annotating this information in a /** @deprecated */ PHP Doc tag.

This approach was not as perfect, because the Reflection API, more specifically the ReflectionFunctionAbstract::isDeprecated() method does not return the deprecation status with the @deprecated PHP Doc annotation. With the new #[Deprecated] attribute, if a PHP symbol is deprecated, the isDeprecated method returns true if the attribute is present.


Example with a #[Deprecated] function:

#[Deprecated]
function my_deprecated_function(): void {
    echo "Called";
}

my_deprecated_function();
Deprecated: Function my_deprecated_function() is deprecated in ... on line ...
Called

Example with a #[Deprecated] class method:

class Test {
    #[Deprecated]
    public function myMethod(): void {}
}

new Test()->myMethod();
Deprecated: Method Test::myMethod() is deprecated in ... on line ...

Example with a #[Deprecated] class constant:

class Test {
    #[Deprecated]
    public const int TEST = 42;
}

echo Test::TEST;
Deprecated: Constant Test::TEST is deprecated in ... on line ...
42

Example with a #[Deprecated] Enum member:

enum MyEnum {
    #[Deprecated]
    case Test;
}

echo MyEnum::Test->name;
Deprecated: Enum case MyEnum::Test is deprecated in ... on line ...
Test

Applicable targets for #[Deprecated] attribute

The #[Deprecated] attribute can be added to the following targets:

  • Functions
  • Class methods
  • Class constants
  • Enum members
  • Constants (since PHP 8.5)

Notably, the #[Deprecated] attribute can not be used on:

  • Class declarations
  • Function and method parameters

#[Deprecated] attribute synopsis

#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION|Attribute::TARGET_CLASS_CONSTANT)]
final class Deprecated
{
    public readonly ?string $message;
    public readonly ?string $since;

    public function __construct(?string $message = null, ?string $since = null) {}
}

The Deprecated attribute class is declared in the global namespace. When applying the attribute, it can also be used as a fully-qualified class name: #[\Deprecated].


Specifying a custom deprecation message

By default, when a PHP symbol is attributed with the #[Deprecated] attribute, it emits a %s is deprecated deprecation message.

However, it is possible to customize this message using the two optional parameters supported by the #[Deprecated] attribute.


Example with $message parameter:

#[Deprecated("use bar instead")]
function foo(): void {}

foo();
Deprecated: Function foo() is deprecated, use bar instead in ... on line ...

Example with $message and $since parameters:

#[Deprecated('use bar instead', 'v42.16.15')]
function foo(): void {}

foo();
Deprecated: Function foo() is deprecated since v42.16.15, use bar instead in ... on line ...

Example with $message and $since as named parameters:

#[Deprecated(message: 'use bar instead', since: 'v42.16.15')]
function foo(): void {}

foo();
Deprecated: Function foo() is deprecated since v42.16.15, use bar instead in ... on line ...

Example with only $since parameter:

#[Deprecated(since: 'v42.16.15')]
function foo(): void {}

foo();
Deprecated: Function foo() is deprecated since v42.16.15 in ... on line ...

Reflection Functionality Changes

The new #[Deprecated] attribute does not introduce any Reflection API changes. However, the Reflection API can now return the deprecated status for user-land PHP symbols using this attribute:

#[Deprecated]
function my_deprecated_function(): void {}
$reflector = new ReflectionFunction('my_deprecated_function');
$reflector->isDeprecated(); // true

This change is effective for class methods (ReflectionMethod::isDeprecated) and class constants/Enum members (ReflectionClassConstant::isDeprecated()) as well. Note that the ReflectionClassConstant class is new in PHP 8.4.

Replacing exiting deprecation mechanisms

PHP applications running PHP 8.4 and later can safely replace deprecation mechanisms for user-land PHP functions and classes with the new #[Deprecated] attribute:

+ #[Deprecated('use bar instead', 'v42.16.15')]
  function foo(): void {  
-   trigger_error('Function foo() is deprecated since v42.16.15, use bar instead', E_USER_DEPRECATED);  
  }  

Backward Compatibility Impact

Unless a user-land PHP application declares a PHP class named Deprecated in the global namespace, this change should not cause any backward compatibility impact.

Any PHP symbol with the #[Deprecated] attribute will continue to work on older PHP versions, but they will not trigger deprecation messages on older PHP versions.

To consistently emit deprecation messages on PHP 8.4+ and older PHP versions, the applications have to emit the deprecation notice within the function or class method itself.

#[Deprecated('use bar instead', 'v42.16.15')]
function foo(): void {
    if (\PHP_VERSION_ID < 80400) {
        trigger_error('Function foo() is deprecated since v42.16.15, use bar instead', E_USER_DEPRECATED);
    }
}

RFC Discussion Implementation