PHP 8.4 polyfill for Deprecated attribute is not compatible with PHP 8.0
deprecated - How to deprecate a function in PHP? - Stack Overflow
PHP 8.2 Dynamic Properties Deprecated: how to use them anyway in a compatible way - Stack Overflow
Why #[Deprecated] is still not a thing?
Videos
Generally speaking you can flag a method as deprecated to give your users warnings about code that will not work in future versions. I think the best way is to use trigger_error along with some phpdoc.
/**
* @deprecated
*
* @return $this
*/
public function oldMethod()
{
trigger_error('Method ' . __METHOD__ . ' is deprecated', E_USER_DEPRECATED);
return $this;
}
The @deprecated phpdoc is important because many IDEs like PHPStorm recognise it and strike the method name if you try to use it, so you notice that is deprecated before actually running your code.
It will look more or less like this:

Beside the phpdoc you can make sure the user gets a warning by triggering the right error at runtime. Just make sure you use the right constant (i.e. E_USER_DEPRECATED).
E_DEPRECATED is instead used internally by PHP thus you should not be using it. More information here.
trigger_error()
function my_deprecated_function() {
trigger_error("Deprecated function called.", E_USER_NOTICE);
// do stuff.
}
As suggested by ADyson, the solution is to use the #[AllowDynamicProperties] attribute just above the class definition.
Classes marked with #[AllowDynamicProperties] as well as their children can continue using dynamic properties without deprecation or removal.
For classes that intentionally don't have a fixed set of properties, it's possible to either implement magic __get()/__set() or mark the class using the #[AllowDynamicProperties] attribute. Marking a class with #[AllowDynamicProperties] is fully backwards-compatible with earlier PHP versions, because prior to PHP 8.0 this would be interpreted as a comment, and the use non-existent classes as attributes is not an error.
This is a full example, as contained in this github repository that I've created to test this feature on Traits and Extended Classes
<?php
namespace App\Classes;
/**
* Use the fully-qualified AllowDynamicProperties, otherwise the #[AllowDynamicProperties] attribute on "MyClass" WILL NOT WORK.
*/
use \AllowDynamicProperties;
#[AllowDynamicProperties]
class MyClass
{
/**
* Dynamic attributes will work with no deprecation warnings
*/
public function __construct()
{
$this->first_name = 'George';
$this->last_name = 'Orwell';
}
}
class MyExtendedClass extends MyClass
{
/**
* Even if "MyExtendedClass" is not using #[AllowDynamicProperties], it extends "MyClass", that is using it.
* Dynamic attributes will work with no deprecation warnings
*/
public function __construct()
{
parent::__construct();
}
}
Other noteworthy facts:
- If you're willing to use the
#[AllowDynamicProperties]attribute in non-namespaced contexts, the fully-qualifieduse \AllowDynamicProperties;statement is not strictly needed (this extends the comment of user706420) - If you need a quick and dirty fix (for example, an old codebase) you can use the
class Foo extends \stdClassas suggested by Ale DC: dynamic properties will work as expected.
replace this:
class yourClassName {
for this:
class yourClassName extends \stdClass {
I found the RFC and some pull requests but all seems outdated and not merged. Do you know any recent news about it?