1

I'm trying to make the following class compatible with native PHP serialization, specifically when running on PHP 8.1.

class SerializableDomDocument extends DOMDocument
{
    private $xmlData;

    public function __sleep(): array
    {
        $this->xmlData = $this->saveXML();
        return ['xmlData'];
    }

    public function __wakeup(): void
    {
        $this->loadXML($this->xmlData);
    }
}

It's all fine and dandy on lower PHP versions, but 8.1 yields Uncaught Exception: Serialization of 'SerializableDomDocument' is not allowed whenever such an object is attempted to be passed to serialize() function. Here's a sample of the code that would produce such an exception: https://3v4l.org/m8sgc.

I'm aware of the __serialize() / __unserialize() methods introduced in PHP 7.4, but using them doesn't seem to be helping either. The following piece of code results into the same exception as can be observed here: https://3v4l.org/ZU0P3.

class SerializableDomDocument extends DOMDocument
{
    public function __serialize(): array
    {
        return ['xmlData' => $this->saveXML()];
    }

    public function __unserialize(array $data): void
    {
        $this->loadXML($data['xmlData']);
    }
}

I'm quite baffled by this problem, and would really appreciate any hints. For the time being it seems like the only way forward would be to introduce an explicit normalizer/denormalizer, which would result in a breaking change in the codebase API. I'd like to avoid that.

wazelin
  • 721
  • 11
  • 21
  • And yes, I don't require a full-fledged serialization here, just the XML representation is sufficient for the use case. – wazelin Jul 13 '22 at 10:04
  • 1
    I don't know the details but I'd personally work around the problem: maybe the `DomDocument` is not serializable because it contains elements that have cyclic dependencies (maybe `DocumentElement` has references to parent elements...). So instead of extending `DomDocument` you can add a class with a composition that serializes `$domDocument->saveXML()` – krampstudio Jul 13 '22 at 10:14
  • Yes, it might be the case in general, @krampstudio. But I still don't get why PHP 8.1 wouldn't allow me to serialize just that piece of data. Removing `DOMDocument` from the parent would also be a breaking change in the API. So, I would rather go with an external normalizer/denormalizer then. In any case, I'd like to get to the bottom of this issue, and understand why PHP 8.1 suddenly became so picky. – wazelin Jul 13 '22 at 10:22

2 Answers2

2

On 10 Aug 2021, this change was commited to version 8.1 RC1:

Mark DOM classes as not serializable

So you can no longer serialize those classes.

Olivier
  • 13,283
  • 1
  • 8
  • 24
  • Got it, thanks for the reference! Apparently it's gotten into the stable release as well. I wonder why it wasn't listed as a breaking change in php.net/releases/8.1/en.php or similar. – wazelin Jul 13 '22 at 11:43
  • 1
    I've decided to report this new behavior of PHP 8.1 https://github.com/php/php-src/issues/8996. I realize why it was decided to disallow the serialization of such classes, but IMO a custom serialization implementation should still be allowed. – wazelin Jul 13 '22 at 12:33
-1

It seems this is related to invalid methods or invalid XML content in your DOMDocument. If you do not use it, this works just fine https://3v4l.org/K91Vv

  • But the whole point is to have an instance of DOMDocument here ;) – wazelin Jul 13 '22 at 10:21
  • I mean, your code will work even if you removed the sleep/wakeup methods, as it's just a generic PHP class' instance serialization. https://3v4l.org/eceoH – wazelin Jul 13 '22 at 10:30