I recently ran into an interesting problem as a result of using PHP’s serialize/unserialize functionality in a … well, a stupid way.

Background
For a brief background, I was working on a feature using a bunch of different classes. These classes could be manipulated by the end-user by changing around options, adding and removing items from lists, and so on. I thought it would be simple and convenient to just serialize these objects right into the database (I was working within a schema and was limited to using a single text blob, so one way or another I was going to be serializing data).

The problem
Originally, my classes used nothing but private members and accessors where needed. More recently, I wanted to change some of these private members to public, and when I did so my existing serialized objects broke! What I found was this:

When PHP attempts to unserialize() data containing private members into a class that contains public members of the same name, it produces an object that has both the private and public members of the same name.

So I ended up with an object who had two members, both with the same name, and $this->member was only returning the public member. The private member, which actually held information, was inaccessible. I looked for some magic __wakeup hackery to work around this but failed. Ultimately, since my code changes were now relying on public behavior, I used __get and __set to mimic it, along with a comment block explaining why I have all private members, and all exposed directly via __get and __set. Ugly, ugly stuff.

The lesson
Be careful what you do with serialized data, especially if you’re planning to keep it around for a while. You can modify the methods of your serialized class all you want, since methods are not serialized, but your data structure (the members) may become much trickier to update in the future.

I didn’t test this all fully, so I’m not sure what exactly is required to trigger this problem. For example, I know that replacing serialized public members with private members causes problems… what about the other direction? What about removing a public member from the class – would this cause the serialized public member to show up anyhow? I’m guessing it would.

« Older entries