PHP: невозможно десериализовать объект php, который теперь реализует интерфейс \ Serializable

Согласно документы

when an old instance of a class that implements this interface now, which had been serialized before the class implemeted the interface, is unserialized, __wakeup() is called instead of the unserialize method, which might be useful for migration purposes.

Я подумал, что это довольно умно и полезно, и хотел это проверить. К сожалению, у меня это не сработало, и мне интересно, что я делаю не так или есть ошибка.

Код теста:

//class Foo
class Foo implements \Serializable
{
    public $a = 'lorem';

    public function __wakeup()
    {
        fprintf(STDOUT, "in %s\n", __METHOD__);
    }

    public function serialize()
    {
        fprintf(STDOUT, "in %s\n", __METHOD__);

        return serialize([
            $this->a,
        ]);
    }

    public function unserialize($serialized)
    {
        fprintf(STDOUT, "in %s\n", __METHOD__);

        list(
            $this->a,
        ) = unserialize($serialized);
    }
}

//$foo = new Foo();
//var_dump(serialize($foo));
//exit;

$serialised = 'O:3:"Foo":1:{s:1:"a";s:5:"lorem";}';
//$serialised = 'C:3:"Foo":22:{a:1:{i:0;s:5:"lorem";}}';

$foo = unserialize($serialised);
var_dump($foo);

Вылетает с:

Warning: Erroneous data format for unserializing 'Foo' in /in/SHaCP on line 39
Notice: unserialize(): Error at offset 13 of 34 bytes in /in/SHaCP on line 39
bool(false)

По сути, я сериализовал объект $foo без интерфейса \Serializable и с ним. Затем добавил интерфейс и попытался в unserialize() сериализовать объект в предыдущей форме (обратите внимание, что сериализованная строка, начинающаяся с O, не имеет интерфейса, а строка, начинающаяся с C, - с интерфейсом).

Что-то я здесь делаю не так? А может я неправильно понял документацию?

Интересно, что код отлично работает на hhvm на 3v4l.org

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
0
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это ГЛАВНОЕ различие между сериализацией по умолчанию и сериализацией из интерфейса - по умолчанию он сериализует весь объект, но с реализацией интерфейса вы определяете, как сериализовать уже созданные атрибуты объекта.

Таким образом, результирующая строка будет отличаться из-за внутренней реализации - как вы можете видеть, в одном случае она начинается с «O», а в другом - с «C». Из-за этого вам придется снова делать его сохранение.

В документах, на которые я ссылался, говорится, что мне не нужно сохранять его снова, если я добавлю интерфейс в свой класс. Документы говорят, что в этом случае он автоматически вызовет __wakeup() вместо unserialize(). Вы пытаетесь сказать, что документы неправильные?

d-ph 13.04.2018 13:25

Здесь не сказано, что так будет работать, здесь говорится только о миграции. Возможно, вы заметили второй комментарий о проблеме, с которой сейчас столкнулись. Вы можете использовать пример, приведенный Оливье, для адаптации к вашим потребностям, учитывая, что вы знаете, для каких классов его добавить.

Daniel Protopopov 13.04.2018 14:20

Не могли бы вы дать мне ссылку на второй комментарий, который я, возможно, заметил? Если вы имеете в виду этот комментарий, то он говорит, что он должен работать именно так, как я объяснил (и как объясняется в документации). комментарий Оливье не имеет отношения к тому, что я здесь описываю. Я прочитал отрывок из документации, который я цитировал снова 10 раз медленно, и мне все еще кажется, что php должен вызывать __wakeup() вместо unserialize() в моем случае.

d-ph 13.04.2018 15:03

Я снова прочитал этот комментарий и понял, что комментатор специально использовал наследование для достижения «обратно совместимого» поведения. Я не уверен, использовал ли он наследование, чтобы что-то доказать, или это было абсолютно необходимо для того, чтобы решение работало. Если использование наследования необходимо, то я бы сказал, что документы неполные - в нем должно быть конкретно указано, что для обработки BC необходимо использовать наследование. Я оставлю этот вопрос открытым некоторое время и приму ваш ответ, если больше никому нечего добавить.

d-ph 13.04.2018 15:12

Вы можете попробовать добавить комментарий на странице PHP или открыть вопрос в их группах. Это не очевидная вещь, и она того стоила бы.

Daniel Protopopov 13.04.2018 19:20

Другие вопросы по теме