Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

php serializing objects whose properties evolve (object evolution)

This is my first question on SO, though I've searched substantially; I apologize if this has already been touched on.

The question/issue has to do with PHP's serialize() functionality. I am using serialization to store objects in a database. For example:

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";}}

Now, later on in the project life, I want to modify my class, First, to have a new property: $SomethingElse that will also correspond to a Something object.

The question is, for my old/existing objects, when I unserialize to the new version of my First class, it seems that the only way to initialize the new property (SomethingElse) is to look for it in the __wakeup() method. In which case, I need to document any new properties there. Is this correct? Properties need to be treated as in the constructor, having their initial value set (which ultimately duplicates the code).

I find that if I initalize the variable when declaring it, then it will get picked up by unserialize, for example, if I changed the Something class to:

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. ) ) 

But you cannot initialize new properties to objects when declaring them, is has to be done in the constructor (and __wakeup()?).

I hope I explained this well enough. I want to know if there's some programming pattern around this that I am missing, or if duplicating initialization code (or referencing an init method) in __wakeup() is typical, or if I simply need to be prepared to migrate old objects to new versions via. migration scripts.

Thanks.


Update: In thinking about what was said by the commenters so far, I thought I'd post the updated First class with an init() method:

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 ) ) 

So really I'm not sure, because that seems like a workable pattern to me. As classes gain new properties they take their default values upon first restoration.

like image 558
Dan L Avatar asked Nov 04 '22 03:11

Dan L


1 Answers

Good question! It cannot been answered in general. And I would say, that's not just related to serialize().. When you have a SQL database, and your code changes it will not work with old data too. That's a common problem of version management with data (bases).

When integrating data from an older software version into a newer one, you'll mostly have the problem that old data has to be translated into a newer format. That's even true with config files etc...

It is usual to write a script that translates the old data into the new format in such cases. I've done this a couple of years at work when creating upgrade packages for a PHP 'firmware' of a server product. :) And so do the most package managers on Linux distributions.

Note: If you will be safe against data loss between upgrades you'll have to take care during development and have the 'upgradability' of data in mind.


Update: I think serialized data can make the update process of data even worse. What is if you serialize a class and the rename it? will be hard to retrieve the data. I never thought about this but it sounds like a problem in case of version upgrades.

like image 101
hek2mgl Avatar answered Nov 09 '22 15:11

hek2mgl