Согласно документы
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






Это ГЛАВНОЕ различие между сериализацией по умолчанию и сериализацией из интерфейса - по умолчанию он сериализует весь объект, но с реализацией интерфейса вы определяете, как сериализовать уже созданные атрибуты объекта.
Таким образом, результирующая строка будет отличаться из-за внутренней реализации - как вы можете видеть, в одном случае она начинается с «O», а в другом - с «C». Из-за этого вам придется снова делать его сохранение.
Здесь не сказано, что так будет работать, здесь говорится только о миграции. Возможно, вы заметили второй комментарий о проблеме, с которой сейчас столкнулись. Вы можете использовать пример, приведенный Оливье, для адаптации к вашим потребностям, учитывая, что вы знаете, для каких классов его добавить.
Не могли бы вы дать мне ссылку на второй комментарий, который я, возможно, заметил? Если вы имеете в виду этот комментарий, то он говорит, что он должен работать именно так, как я объяснил (и как объясняется в документации). комментарий Оливье не имеет отношения к тому, что я здесь описываю. Я прочитал отрывок из документации, который я цитировал снова 10 раз медленно, и мне все еще кажется, что php должен вызывать __wakeup() вместо unserialize() в моем случае.
Я снова прочитал этот комментарий и понял, что комментатор специально использовал наследование для достижения «обратно совместимого» поведения. Я не уверен, использовал ли он наследование, чтобы что-то доказать, или это было абсолютно необходимо для того, чтобы решение работало. Если использование наследования необходимо, то я бы сказал, что документы неполные - в нем должно быть конкретно указано, что для обработки BC необходимо использовать наследование. Я оставлю этот вопрос открытым некоторое время и приму ваш ответ, если больше никому нечего добавить.
Вы можете попробовать добавить комментарий на странице PHP или открыть вопрос в их группах. Это не очевидная вещь, и она того стоила бы.
В документах, на которые я ссылался, говорится, что мне не нужно сохранять его снова, если я добавлю интерфейс в свой класс. Документы говорят, что в этом случае он автоматически вызовет
__wakeup()вместоunserialize(). Вы пытаетесь сказать, что документы неправильные?