【问题标题】:PHP: Can't unserialise php object that now implements the \Serializable interfacePHP:无法取消序列化现在实现 \Serializable 接口的 php 对象
【发布时间】:2018-04-13 09:35:43
【问题描述】:

根据the docs

当现在实现此接口的类的旧实例(在该类实现接口之前已被序列化)被反序列化时,将调用 __wakeup() 而不是 unserialize 方法,这可能对迁移有用。

我认为这非常聪明和有用,并想检查一下。不幸的是,它对我不起作用,我想知道是我做错了什么还是有错误。

测试代码:

//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开头的是带接口的)。

我在这里做错了吗?还是我误解了文档?

有趣的是,代码runs fine on hhvm at 3v4l.org

【问题讨论】:

    标签: php serialization


    【解决方案1】:

    这是默认序列化和接口序列化之间的主要区别 - 默认情况下它会序列化整个对象,但通过接口的实现,您可以定义如何序列化已创建对象的属性。

    因此,由于内部实现,生成的字符串会有所不同 - 正如您所见,在一种情况下它以“O”开头,而在另一种情况下它是“C”。因此,您将不得不再次保存它。

    【讨论】:

    • 我提到的文档说如果我将接口添加到我的类中,我不需要再次保存它。文档说在这种情况下它会自动调用__wakeup() 而不是unserialize()。您是想说文档有误吗?
    • 它并没有说它会以这种方式工作,它只谈论迁移。您可能已经注意到关于您现在遇到的问题的第二条评论。鉴于您知道要将其添加到哪些类,您可以使用 Olivier 给出的示例来适应您的需求。
    • 能否提供我可能注意到的第二条评论的链接?如果您的意思是this comment,那么它说它应该完全按照我的解释(以及文档的解释)工作。 comment from Olivier 与我在这里描述的内容无关。我已经阅读了 10 次缓慢再次引用的文档摘录,但在我看来,php 应该调用 __wakeup() 而不是 unserialize()。
    • 我再次阅读this comment 并意识到评论者专门使用继承来实现“向后兼容”行为。我不确定他是否使用继承只是为了证明某些事情,或者解决方案是否绝对有必要工作。如果必须使用继承,那么我会说文档不完整——它应该特别提到必须使用继承来处理 BC。如果没有其他人要补充任何内容,我会暂时保留这个问题并接受您的回答。
    • 您可以尝试在 PHP 页面上添加评论或在他们的组中打开问题。这不是一件显而易见的事情,而且是值得的。
    猜你喜欢
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    • 2014-01-01
    • 2018-03-19
    • 1970-01-01
    • 2012-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多