我有一些包含序列化对象的数据库行。
我想要反序列化它们,但是类已经更改,某些属性变为私有,因此反序列化操作不再有效。
是否有一种方法可以强制反序列化成数组或stdClass?(或任何不会在反序列化时导致错误的内容)
我希望避免使用脚本迁移数据。我宁愿与旧格式中序列化的对象保持向后兼容性。
我有一些包含序列化对象的数据库行。
我想要反序列化它们,但是类已经更改,某些属性变为私有,因此反序列化操作不再有效。
是否有一种方法可以强制反序列化成数组或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'
我在这个问题上咨询了我的压抑记忆(我曾经遇到过类似的问题)并想起了另一个解决方案:
所以你有一个名为$a
的private
属性的SomeClass
。
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"
}
*/
__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 中有旧的类吗?