我有包含序列化对象的数据库行。
我想反序列化这些,但是类已经改变,一些属性变为私有,因此反序列化不再有效。
有没有办法强制反序列化到数组或stdClass? (或反序列化时不会导致错误的任何内容)
我想避免使用脚本迁移数据。我宁愿向后兼容以旧格式序列化的对象。
答案 0 :(得分:5)
不是真的,或者至少我会害怕在生产中使用这样的东西。
但是,unserialize
将使用自动加载系统或unserialize_callback_func
ini设置中指定的函数名称。因此,通过一点点黑客攻击你可以做到这一点:
// 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
魔法。您需要的数据存在于对象中,但不在私有属性下,而是在类似命名的公共属性中。您无法通过$this->a
达到此目的,因为它会找错页面,
但是方法get_object_vars()
将返回这些属性,您可以在__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();
我认为不用说你应该为自己避免进一步的麻烦并将数据转换成某种专用的数据交换格式。
答案 1 :(得分:-1)
除了手动调整数据库本身的数据(这总是一个冒险的命题)之外,我认为您唯一的选择是将类代码回滚到旧版本,提取数据,然后将其重新存储到更多在未来的代码修订中可以更容易处理的合理方法。
您的SVN / GIT / CVS中有旧课程,对吗?