Search code examples
phplaravelphp-8.4

Property hook not found when serializing an object using __sleep


I noticed something strange when using the combination property hooks with the magic __sleep() method. I have no idea whether I incorrectly use hooks or that this is a bug in PHP.

See the following example:

class A {
    private array $foo = ['baz' => 10];

    public int $bar {
        get => $this->foo['baz'];
        set {
            $this->foo['baz'] = $value;
        }
    }
    
    public function __sleep()
    {
        // ...
        return array_keys(get_object_vars($this));
    }
}

$a = new A;
$a->bar = 20;

var_dump(unserialize(serialize($a)));

This causes the following warning:

serialize(): "bar" returned as member variable from __sleep() but does not exist

Which is strange, because it works as expected and the property does exist. Reproducable example: https://3v4l.org/V1S5i#v8.4.3.

This is an issue because in the framework I use (Laravel), this warning is promoted to an exception and breaks my application.


Solution

  • No idea how much nitpicking about the word "member" in the error message is necessary. The diagnostic message is likely a bit surprising indeed, but hooks are new, too. Reading __sleep() it may stem from the warning returning the member name of an inaccessible parents private property. But I've not looked into the source.

    If a bug, then it should be possible to serialize the property. As analyzed in comments already, it's a virtual one, and therefore it makes not much sense to serialize it (so not/a bug).

    Undocumented:

    In your posted example, you can replace get_object_vars() with get_mangled_object_vars(). It silently discards uninitialized typed properties (documented) and virtual properties with hooks as it seems (just learned).

    Demo


    References