PHP 8.2: Dynamic Properties are deprecated

Version8.2
TypeDeprecation

In PHP classes, it is possible to dynamically set and retrieve class properties that are not declared. These properties do not adhere to a specific (similar to typed properties), and it requires the use of __get() and __set() magic methods to effectively prevent or control how dynamic properties are set and retrieved.

class User {
    private int $uid;
}

$user = new User();
$user->name = 'Foo';

In the snippet above, the User class does not declare a property with name name, but because dynamic properties are allowed, PHP allows setting it.

While dynamic properties provide the flexibility in creating classes such as value objects without a strict class declaration, it opens the possibility of potential bugs and unexpected behaviors in applications . For example, a typo in a statement that sets a property could go unnoticed because PHP silently allows all dynamic properties.


In PHP 8.2 and later, setting a value to an undeclared class property is deprecated, and emits a deprecation notice the first time the property is set during the lifetime of the application execution.

class User {
    private int $uid;
}

$user = new User();
$user->name = 'Foo';
Deprecated: Creation of dynamic property User::$name is deprecated in ... on line ...

Setting the properties from within the class also emits the deprecation notice:

class User {
    public function __construct() {
        $this->name = 'test';
    }
}

new User();
Deprecated: Creation of dynamic property User::$name is deprecated in ... on line ...

There are legitimate use cases of dynamic properties, such as value objects derived from a dynamic JSON response, or configuration objects that allow arbitrary values.

Ideally, classes should declare the dynamic properties in the class to avoid the deprecation notice. It is not required to declare the property with a property type.

Exempted Dynamic Property Patterns

There are three exceptions to this deprecation. Utilizing one of the approaches below avoids the deprecation notice.

  1. Classes with #[AllowDynamicProperties] attribute.
  2. stdClass and its sub-classes
  3. Classes with __get and __set magic methods

Classes with #[AllowDynamicProperties] attribute

PHP 8.2 introduces a new attribute in the global namespace named #[AllowDynamicProperties]. Classes declared with this attribute signals PHP to not emit any deprecation notices when setting dynamic properties on objects of that class.

Child classes automatically inherit the #[AllowDynamicProperties] attribute from parent class.

The snippet below declares a User class with #[AllowDynamicProperties] attribute, and does not emit any deprecation notices even though it sets properties dynamically.

+ #[AllowDynamicProperties]
  class User {
      private int $uid;
  }

  $user = new User();
  $user->name = 'Foo';

stdClass and its sub-classes

PHP uses stdClass as the base class when it coerces data to objects, when decoding JSON objects, etc. In PHP 8.2, the #[AllowDynamicProperties] attribute is internally added to the stdClass class. This means setting dynamic properties on stdClass objects or any classes that extend stdClass does not emit dynamic property deprecation notices.

$object = new stdClass();
$object->foo = 'bar';
class User extends stdClass {}

$object = new User();
$object->foo = 'bar';

Neither of the snippets above emit dynamic property deprecation notices because the stdClass internally has the #[AllowDynamicProperties] attribute.

Classes with __get and __set magic methods

Classes that declare a __set magic method are excluded from the dynamic property declaration. It might be necessary to couple it with a __get method to create a practically useful class.

class User {
    public function __set(string $name, mixed $value): void {

    }
}

$user = new User();
$user->name = 'test';

The snippet above does not emit a deprecation notice because the User class implements the __set magic method.


Note that setting a dynamic property from within the __set method is still deprecated:

class User {
    public function __set(string $name, mixed $value): void {
        $this->{$name} = $value;
    }
}

$user = new User();
$user->name = 'test';
Deprecated: Creation of dynamic property User::$name is deprecated in ... on line ...

Associating object data with WeakMaps

PHP 8.0 introduced WeakMaps to PHP. Applications that set dynamic properties to associate auxiliary data may consider using WeakMaps. This might improve the clarity and maintainability of the code, while avoiding the dynamic property deprecation notice.


For example, the following snippet stores a dynamic property called processed. This property is not declared on the Event class, and does not belong to the Event class itself.

$event = new Event();
$event->processed = true; // <-- dynamic property

$is_processed = !empty($event->processed);

With WeakMaps, it is possible to associate data in a WeakMap. When the Event object is dropped from the scope, the associated data will be removed automatically.

  $event = new Event();
+ $processed_events = new WeakMap();

- $event->processed = true; // <-- dynamic property
+ $processed_events[$event] = true;

- $is_processed = !empty($event->processed);
+ $is_processed = !empty($processed_events[$event]);

Backwards Compatibility Impact

The deprecation notice is emitted on PHP 8.2 and later. In PHP 9.0, dynamic properties will result in a fatal error.

It is possible to programmatically emit a deprecation in older versions in the interest of consistency across multiple PHP versions.

Related Changes


RFC Discussion Implementation