Update Properties While Cloning Object in PHP 8.5

Update Properties While Cloning Object in PHP 8.5

Before PHP 8.5, working with immutable objects or readonly classes required a somewhat verbose pattern to create modified copies of existing objects. Since readonly properties cannot be changed after construction, if you wanted a new instance with one property updated, you had to manually gather all existing values, replace the desired property, and call the constructor again. This approach works, but can quickly become boilerplate-heavy as the number of properties grows.

For example, consider a simple Time class with three readonly properties:

Time.php

<?php

readonly class Time
{
    public function __construct(public int $hour, public int $minute, public int $second)
    {
    }

    public function withHour(int $hour): self
    {
        $values = get_object_vars($this);
        $values['hour'] = $hour;

        return new self(...$values);
    }
}
<?php

require_once __DIR__.'/Time.php';

$time = new Time(14, 30, 45);
$later = $time->withHour(15);

print_r($later); // Time Object ([hour] => 15 [minute] => 30 [second] => 45)

Here, the withHour method manually collects all the properties of the existing object, updates the hour, and constructs a new Time object. While effective, this pattern requires extra boilerplate code and can become cumbersome for classes with many properties.

Since PHP 8.5, we can simplify this pattern using a new clone syntax. Instead of manually collecting all properties and calling the constructor, we can create a modified copy of an object by cloning it and passing an associative array of property overrides. This makes the "with‑er" pattern much more concise and readable.

Using the previous Time example, the withHour method can now be rewritten as:

Time.php

<?php

readonly class Time
{
    public function __construct(public int $hour, public int $minute, public int $second)
    {
    }

    public function withHour(int $hour): self
    {
        return clone($this, ['hour' => $hour]);
    }
}

This approach eliminates boilerplate code and works seamlessly with readonly properties, allowing multiple properties to be overridden in a single call if needed.

Leave a Comment

Cancel reply

Your email address will not be published.