Reputation: 51
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.
Upvotes: 5
Views: 1533
Reputation: 158080
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.
Upvotes: 2
Reputation: 2452
Last time I had a class with changing properties, I stored all the data in an associative array called $classVar . If you do that, then all variables you add will be tracked with one simple serialize call no matter how many variables you add to that.
When it comes to usage, just check if the variable is initialized and if not, set the default. You could even serialize a classversion variable to handle more complicated cases such as variables not used anymore or variables that need conversion
Upvotes: 0