PHP: Creating a singleton class for serialization
There’s a lot of examples on the internet about creating and using the singleton pattern within your application. From the PHP Docs:
The Singleton pattern applies to situations in which there needs to be a single instance of a class. The most common example of this is a database connection. Implementing this pattern allows a programmer to make this single instance easily accessible by many other objects.
Within any class you want to have use the singleton pattern, just add a getInstance method, like I have in the Obj code listing below. To access that instance use the scope resolution operator:
$obj = Obj::getInstance();
A problem arises when you want to serialize/unserialize that object from the session variable. The issue is this: When unserialize is called, PHP will attempt to reconstruct the object in question – everything will get created properly but the $instance variable will now be NULL because it would be pointing to the object reference from the previous page. So the next time you would call getInstance, the function would return an entirely new object with no serialized data. All the serialized data would exist in whatever variable the unserialize function was assigned to initially.
Once you understand this subtlety fixing the problem is easy. Create a function called setInstance, which takes in an object reference and assigns the object to the static $instance variable within the class. So once you unserialize your object from the session, immediately call setInstance to let the class know the object exists:
$obj = unserialize($_SESSION['SessionControl']);
$obj->setInstance($obj);
The full code listings follow so you can test this out. Someone out there is probably thinking, why not just called setInstance from within the __wakeup function with $this as a parameter? That won’t work, the object won’t serialize properly.
<?php
class Obj {
static private $instance = NULL;
public function __construct() { }
public static function getInstance() {
if (self::$instance == NULL) {
self::$instance = new Obj;
}
return self::$instance;
}
public function setInstance($o) {
self::$instance = $o;
}
public function __sleep() {
return array_keys(get_object_vars($this));
}
public function __wakeup() { }
}
?>
<?php
require 'obj.class.php';
session_start();
if(!empty($_SESSION['SessionControl'])) {
$obj = unserialize($_SESSION['SessionControl']);
$obj->setInstance($obj);
} else {
$obj = Obj::getInstance();
}
function save_session() {
$obj = Obj::getInstance();
$_SESSION['SessionControl'] = serialize($obj);
}
register_shutdown_function(save_session);
?>
Have a second? Check out this great Canadian Health & Living Store based in Toronto


December 7th, 2007 at 5:08 pm
Does not seem to be working and tried everything and still does not work.
The first page load serializes ok. The second page load, where the first part of if statement is processed, shows up blank. How does static variables from first page get loaded on unserializing?
February 26th, 2008 at 4:31 am
Thanks, you saved me a lot of time! Your example works smoothly for me.
@ploceus: Static variables are not saved on serialization and, thus, not loaded on unserialization. However, one could try to mimic the feature by storing them manually in the object with __sleep() function and restoring in the __wakeup() function or, if that doesn’t work, in the setInstance(). Personally, the only static variable I have is the reference to an instance of my class, and everything works as it should.
February 26th, 2008 at 6:02 am
@ploceus: Well… I guess, now I can imagine what might have caused a trouble for you.
In PHP 5.1.6 you cannot call register_shutdown_function from a static class method. Instead, you have to pass an array of the class name and the function name. An explanation and examples are found here. They say this works in PHP 4 too!
As of PHP 5.2.3 one can simply pass ‘ClassName::methodName’, and it would work.
July 16th, 2008 at 12:42 pm
try this:
public function __wakeup()
{
if( isset($this->me) ) self::$instance = $this->me;
}
public function __sleep()
{
$this->me = self::$instance;
return array_keys(get_object_vars($this));
}
July 16th, 2008 at 1:10 pm
For me that works fine. Even if it might not 100% be the idea of a singleton pattern