3

我有包含序列化对象的数据库行。

我想反序列化这些,但是类已经改变,一些属性变成私有的,所以反序列化不再起作用。

有没有办法强制反序列化为数组或 stdClass?(或任何在反序列化时不会导致错误的东西)

我想避免使用脚本迁移数据。我宁愿向后兼容以旧格式序列化的对象。

4

2 回答 2

10

不是真的,或者至少我会非常害怕在生产中使用这样的东西。但是,unserialize将使用自动加载系统或unserialize_callback_funcini 设置中指定的函数名称。因此,只需稍加修改,您就可以完成这项工作:

// this a serialized object with the class "SomeMissingClass"
$str = 'O:16:"SomeMissingClass":1:{s:1:"a";s:1:"b";}';
ini_set('unserialize_callback_func', 'define_me'); // set your callback_function

// unserialize will pass in the desired class name
function define_me($classname) {
    // just create a class that has some nice accessors to it
    eval("class $classname extends ArrayObject {}");
}
$object = unserialize($str);
print $object['a']; // should print 'b'

您可以使用类似的方法将数据迁移到更方便的格式。

更新:

我已经咨询了我被压抑的记忆(我曾经遇到过这样的事情)并记住了另一个解决方案:

所以你有SomeClass一个private名为$a

class SomeClass {
    private $a;
    public function getA(){
        return $this->a;
    }
}

你有它的序列化版本:

$str = 'O:9:"SomeClass":1:{s:1:"a";s:1:"b";}';

当您对其进行反序列化并转储结果时,它将如下所示,这是不好的:

$a = unserialize($str);
var_dump($a->getA()); // prints 'null'
var_dump($a);
/* 
prints:
object(SomeClass)#1 (2) {
   ["a":"SomeClass":private]=>
   NULL
   ["a"]=>
   string(1) "b"
}
*/

现在,当一个对象被反序列化时,php 将调用它的__wakeup魔法方法。您需要的数据在对象中,但不在私有属性下,而是在类似名称的公共属性下。您无法使用 the 来实现,$this->a因为它会查找错误的属性,但是该方法get_object_vars()将返回这些属性,您可以在 a 中重新分配它们__wakeup()

class SomeClass {
    private $a;
    public function getA(){
        return $this->a;
    }
    public function __wakeup(){
        foreach (get_object_vars($this) as $k => $v) {
            $this->{$k} = $v;
        }
    }
}
$str = 'O:9:"SomeClass":1:{s:1:"a";s:1:"b";}';
$a = unserialize($str);
print $a->getA();

我认为不用说您应该为自己省去更多的麻烦,并将您的数据转换为一些专用的数据交换格式。

于 2013-06-27T08:34:03.153 回答
-1

除了手动修改数据库本身中的数据(这始终是一个冒险的提议)之外,我认为您唯一的选择是将类代码回滚到旧版本,提取数据,然后以更明智的方式重新存储它在以后的代码修订中可以更容易地处理。

您的 SVN/GIT/CVS 中确实有旧类,对吗?

于 2013-06-27T08:35:14.783 回答