我有包含序列化对象的数据库行。
我想反序列化这些,但类已经更改,一些属性变为私有属性,因此反序列化不再有效。
有没有办法强制对数组或stdClass进行反序列化?(或任何在反序列化时不会导致错误的东西)
我希望避免使用脚本迁移数据。我宁愿与以旧格式序列化的对象具有向后兼容性。
不是真的,或者至少我会非常害怕在生产中使用这样的东西。但是,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
具有名为$a
的private
属性
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();
我认为不用说,你应该省去更多的麻烦,将你的数据转换为一些专用的数据交换格式。
除了手动处理数据库中的数据(这总是一个有风险的提议)之外,我认为您唯一的选择是将类代码回滚到旧版本,提取数据,然后以更明智的方式重新存储,以便在未来的代码修订中更容易处理。
你的SVN/GIT/CVS中确实有旧的类,对吧?