Timeline Taxi Out now: my sci-fi novel Timeline Taxi is published!

Deprecated dynamic properties in PHP 8.2

As is common with minor releases, PHP 8.2 adds some deprecations. Deprecations often are a source of frustration, though it's important to realise they are actually very helpful. I already wrote about dealing with deprecations in general, so if you're already feeling frustrated, maybe it's good to take a look at that post first. Today, I want to focus on one deprecation in particular in PHP 8.2: deprecated dynamic properties.

So first things first, what are dynamic properties exactly? Well, they are properties that aren't present on a class' definition, but are set on objects of those classes dynamically, at runtime.

For example this Post class doesn't have a name property, but nevertheless we set it at runtime:

class Post
{
}

// …

$post = new Post();

$post->name = 'Name';

var_dump($post->name); // 'Name'

As of PHP 8.2, these dynamic properties will be deprecated:

// …

$post->name = 'Name';

You'll see this message: Deprecated: Creation of dynamic property Post::$name is deprecated.

# Implementing __get and __set still works!

You might be panicking at this point, because dynamic properties are a big part of meta programming in PHP — many frameworks rely on it!

Not to worry: this new deprecation won't affect any class that implements __get and __set. Classes that implement these magic functions will keep working as intended:

class Post
{
    private array $properties = [];
    
    public function __set(string $name, mixed $value): void
    {
        $this->properties[$name] = $value;
    }
    
    // …
}

// …

$post->name = 'Name';

The same goes for objects of stdClass, they will support dynamic properties just as before:

$object = new stdClass();

$object->name = 'Name'; // Works fine in PHP 8.2

Now some clever readers might wonder: if stdClass still allows dynamic properties, what would happen if you'd extend from it?

Indeed, it is possible to extend from stdClass to prevent the deprecation notice from being shown. However, I'd say this solution is far from ideal:

// Don't do this

class Post extends stdClass
{
}

$post = new Post();

$post->name = 'Name'; // Works in PHP 8.2

# A better alternative

If you really want to use dynamic properties without implementing __get and __set, there is a much better alternative than to extend from stdClass.

The PHP core team has provided a built-in attribute called AllowDynamicProperties. As its name suggests, it allows dynamic properties on classes, without having to rely on sketchy extends:

#[\AllowDynamicProperties]
class Post
{
}

$post = new Post();

$post->name = 'Name'; // All fine

# Closing thoughts

PHP used to be a very dynamic language, but has been moving away from that mindset for a while now. Personally I think it's a good thing to embrace stricter rules and rely on static analysis wherever possible, as I find it leads to writing better code.

I can imagine developers who relied on dynamic properties, who are less happy with this change. If you're in that group, you might find it useful to take a closer look into static analysis. You can check out my Road to PHP: Static Analysis series if you want to learn more!

If you're willing to invest some time in figuring out static analysis, I'm fairly certain that most of you won't ever want to return back to the mess that is a dynamic programming language. With PHP we're lucky that both options are available and that you can migrate gradually towards a stricter type system.

So, yes: this deprecation might be a little painful, but I believe it's for the best of the language to do so. And remember that it won't be a fatal error until PHP 9.0, so there's plenty of time to deal with it.

Noticed a tpyo? You can submit a PR to fix it. If you want to stay up to date about what's happening on this blog, you can subscribe to my mailing list: send an email to brendt@stitcher.io, and I'll add you to the list.