php序列化属性发生变化的对象(对象进化)


php serializing objects whose properties evolve (object evolution)

这是我关于SO的第一个问题,尽管我已经搜索了很多;如果这件事已经被提及,我深表歉意。

这个问题与PHP的serialize((功能有关。我正在使用序列化将对象存储在数据库中。例如:

class Something {
  public $text = "Hello World";
}
class First {
  var $MySomething;
  public function __construct() {
    $this->MySomething = new Something();
  }
}
$first_obj = new First();
$string_to_store = serialize($first_obj);
echo $string_to_store
//  Result:  O:5:"First":1:{s:11:"MySomething";O:9:"Something":1:{s:4:"text";s:11:"Hello World";}}

现在,在项目生命的后期,我想修改我的类First,使其具有一个新属性:$SomethingElse,它也将对应于Something对象。

问题是,对于我的旧/现有对象,当我将其取消序列化到First类的新版本时,初始化新属性(SomethingElse(的唯一方法似乎是在__wakeup((方法中查找它。在这种情况下,我需要记录那里的任何新属性 这是正确的吗 属性需要像在构造函数中一样处理,设置它们的初始值(这最终会复制代码(。

我发现,如果我在声明变量时初始化它,那么它将被取消初始化所获取,例如,如果我将Something类更改为:

class Something {
  public $text = "Hello World";
  public $new_text = "I would be in the unserialized old version.";
}
...
$obj = unserialize('O:5:"First":1:{s:11:"MySomething";O:9:"Something":1:{s:4:"text";s:11:"Hello World";}}');
print_r($obj);
//  Result:  First Object ( [MySomething] => Something Object ( [text] => Hello World [new_text] => I would be in the unserialized old version. ) ) 

但是在声明对象时不能将新属性初始化为对象,需要在构造函数中完成(和__wakeup((?(。

我希望我解释得足够好。我想知道我是否缺少一些编程模式,或者在__wakeup((中复制初始化代码(或引用init方法(是否很常见,或者我是否只需要准备好通过将旧对象迁移到新版本。迁移脚本。

谢谢。


更新:考虑到目前为止评论者所说的内容,我想我应该用init((方法发布更新后的First类:

class Something {
  public $text = "Hello World2";
  public $new_text = "I would be in the unserialized old version.2";
}
class First {
  var $MySomething;
  var $SomethingElse;
  public function __construct() {
    $this->init();
  }
  public function __wakeup() {
    $this->init();
  }
  private function init() {
    if (!isset($this->MySomething)) {
      $this->MySomething = new Something();
    }
    if (!isset($this->SomethingElse)) {
      $this->SomethingElse = new Something();
    }
  }
}
$new_obj = unserialize('O:5:"First":1:{s:11:"MySomething";O:9:"Something":1:{s:4:"text";s:11:"Hello World";}}');
print_r($new_obj);
//  Result:  First Object ( [MySomething] => Something Object ( [text] => Hello World [new_text] => I would be in the unserialized old version.2 ) [SomethingElse] => Something Object ( [text] => Hello World2 [new_text] => I would be in the unserialized old version.2 ) ) 

所以我真的不确定,因为这对我来说似乎是一个可行的模式。当类获得新的属性时,它们在第一次恢复时会取默认值。

好问题!这个问题不能笼统地回答。我想说,这不仅仅与serialize((有关。。当您有一个SQL数据库,并且您的代码发生更改时,它也将无法使用旧数据。这是使用数据(基(进行版本管理的常见问题。

当将旧软件版本的数据集成到新软件版本时,您通常会遇到旧数据必须转换为新格式的问题。配置文件等也是如此…

在这种情况下,通常会编写一个脚本,将旧数据转换为新格式。我在为服务器产品的PHP"固件"创建升级包时已经做了几年了。:(Linux发行版上的大多数软件包管理器也是如此。

注意:如果在升级之间可以安全地防止数据丢失,那么在开发过程中就必须小心,并考虑到数据的"可升级性"。


更新:我认为序列化的数据会使数据的更新过程变得更糟。如果序列化一个类并重命名它,会发生什么?将很难检索数据。我从未想过这一点,但在版本升级的情况下,这听起来像是的问题

上次我有一个属性不断变化的类时,我将所有数据存储在一个名为$classVar的关联数组中。如果您这样做,那么无论您添加了多少变量,都将使用一个简单的序列化调用来跟踪您添加的所有变量。

在使用时,只需检查变量是否已初始化,如果未初始化,则设置默认值。您甚至可以序列化classversion变量来处理更复杂的情况,例如不再使用的变量或需要转换的变量