【问题标题】:PHP unserialize an object without the matching classPHP反序列化没有匹配类的对象
【发布时间】:2013-06-27 08:16:35
【问题描述】:

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

我想反序列化这些,但类已更改,某些属性变为私有,因此反序列化不再有效。

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

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

【问题讨论】:

  • 不是讽刺或任何东西,而是:这就是为什么您不将代码存储在数据库中... :)
  • @deceze 阿门。再也不! -_-
  • 这就是为什么不将对象作为序列化字符串存储到数据库的原因。

标签: php serialization


【解决方案1】:

不是真的,或者至少我会非常害怕在生产中使用这样的东西。 但是,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();

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

【讨论】:

  • 哇,既聪明又恐怖!
  • 感谢您的疯狂想法!这太棒了,我将使用它来软迁移到比序列化对象更明智的数据格式:)
【解决方案2】:

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

你的 SVN/GIT/CVS 中确实有旧的类,对吧?

【讨论】:

  • 是的,我愿意,就像我说的,我想避免迁移步骤如果可能
猜你喜欢
  • 1970-01-01
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 2010-10-13
  • 1970-01-01
  • 2014-08-21
相关资源
最近更新 更多