Using the Sleep and Wakeup Functions to Serialize Objects in PHP

Curious about how to serialize your objects inside your beautifully-crafted application? Look no further. Welcome to the second part of the series “Serializing objects in PHP.” This set of three tutorials introduces the fundamentals of objects serialization, and teaches you some advanced concepts regarding this approach, such as using objects in sessions and storing them in database tables.

Introduction

As you’ll surely recall, over the previous article, I explained the basics of serializing objects in PHP. I showed some code samples that illustrated in a simple way the process of converting objects to their string representation (called serialization). I also showed how to reverse this process (that is unserialization), in order to restore these objects to their original state. In the several examples that you saw before, I also exposed some interesting concepts involved in object serialization, such as constructing objects that are capable of saving and restoring themselves via their own methods, which are commonly called self-saving objects.

As a matter of fact, one of the best things about serializing objects in PHP is that this fairly simple concept can be used as the starting point to tackle more advanced concepts, including those related to an object’s persistence and its storage in database tables. In addition, if you’ve been working with sessions for a while, then you’ll know that the PHP built-in session handling mechanism serializes and unserializes objects behind the scenes, whenever they’re registered during a particular session, which means that object serialization is indeed an important topic that must be addressed appropriately.

Now, after refreshing the concepts that I deployed in the first part of this series, it’s time to focus on the topics that I’ll cover in this article, so you’ll know what to expect before you continue reading. In this second part, I’ll explain how to use objects in conjunction with the “__sleep()” and “__wakeup() magic functions respectively, in order to get the most out of them.

Having defined the topics for this new tutorial, let’s move on and continue learning more about object serializing in PHP. Let’s go!

{mospagebreak title=A quick look at how to define self-saving objects}

A good place to start explaining some advanced concepts, such as the use of the “__sleep()” and “__wakeup()” PHP magic functions, and to introduce object persistence, is with precisely listing the definition for the example “ObjectSaver” class that you learned in the previous tutorial.

As you’ll certainly recall, this class was capable of saving and restoring itself via its own methods, which implies that any objects spawned from it can be considered self-saving objects.

Assuming that self-saving objects are pretty familiar to you, here is the corresponding signature of the “ObjectSaver” class, as I defined it originally in the first article. Please have a look:

class ObjectSaver{
    var $objectFile;
    function ObjectSaver($objectFile=’defaultDir/objects.txt’){
        $this->objectFile=$objectFile;
        $this->save();
    }
    // save serialized object to file
    function save(){
        if(!$fp=fopen($this->objectFile,’w')){
            trigger_error(‘Error opening object
file’,E_USER_ERROR);
        }
        if(!fwrite($fp,serialize($this))){
            trigger_error(‘Error writing data to object
file’,E_USER_ERROR);
        }
        fclose($fp);
    }
    // fetch object from file
    function fetch(){
        if(!$obj=unserialize(file_get_contents($this-
>objectFile))){
            trigger_error(‘Error fetching object from
file’,E_USER_ERROR);
        }
        return $obj;
    }
    // display message
    function displayMessage(){
        return ‘This is an object that saves and retrieves itself
via its methods!’;
    }
}

As you learned before, the above class initially exposed the “save()” and “fetch()” methods, which were handy for serializing and unserializing itself, and used a simple text file for storing its status. Naturally, this behavior can be modified easily, in order to use cookies or even a database table for saving different instances of the class.

Additionally, I added to the class the “displayMessage()” method, which can be used for showing a trivial message, in this way demonstrating how an object spawned from this class is capable of restoring itself. With reference to this capability, the below example clearly shows how to use an object which has been instanced from the “ObjectSaver” class:

$objSaver=&new ObjectSaver();
$newObj=$objSaver->fetch();
echo $newObj->displayMessage();

All right, after exemplifying the usage of the above class, I’m going to employ it to demonstrate how to use the “__sleep()” and “__wakeup()” PHP magic functions, in order to create objects that persist across different HTTP requests.

To learn how this will be achieved, please click on the link below and keep reading.

{mospagebreak title=Using the “__sleep()” and “__wakeup()” magic functions}

For those of you new to serializing objects in PHP, let me emphasize an important feature that can be used for different purposes: if you use the “serialize()” function on a specific object, the PHP interpreter will check whether there is a method called “__sleep()” and run its corresponding code prior to any serialization, assuming that this method has been defined.

In a similar way, if the “unserialize()” function is applied to an object, the PHP parser will look for a method named “__wakeup()” and try to execute any code wrapped inside of it, before proceeding to unserialize the object in question.

Since these functions are called transparently by the interpreter, it’s possible to create classes that take advantage of this automated process, in order to perform some useful tasks.

To properly understand the concepts I deployed before, take a look at the following sample class, which displays a simple message each time the “__sleep()” and “__wakeup()” functions are called respectively:

class ObjectSaver{
    var $objectFile;
    function ObjectSaver($objectFile=’defaultDir/objects.txt’){
        $this->objectFile=$objectFile;
        $this->save();
    }
    // save serialized object to file
    function save(){
        if(!$fp=fopen($this->objectFile,’w')){
            trigger_error(‘Error opening object file’,E_USER_ERROR);
        }
        if(!fwrite($fp,serialize($this))){
            trigger_error(‘Error writing data to object
file’,E_USER_ERROR);
        }
        fclose($fp);
    }
    // fetch unserialized object from file
    function open(){
        if(!$obj=unserialize(file_get_contents($this-
>objectFile))){
            trigger_error(‘Error fetching object from
file’,E_USER_ERROR);
        }
        return $obj;
    }
    // define ‘__sleep()’ method
    function __sleep(){
        echo ‘This method was called prior to serializing the
object!<br />’;
        return array_keys(get_object_vars($this));       

    }
    // define ‘__wakeup()’ method
    function __wakeup(){
        echo ‘This method was called after unserializing the
object!<br />’;
    }
}

In this case, I redefined the previous “ObjectSaver” class, and added to its signature the corresponding “__sleep()” and “__wakeup()” methods, so that it will display a basic message whenever they’re called up.

After defining the modified “ObjectSaver” class, a basic — yet illustrative — demonstration of how these magic methods are called by the PHP interpreter is listed below:

// show the functionality of __sleep() and __wakeup() methods
$objSaver=&new ObjectSaver();
$newObj=$objSaver->open();

If you run the above script, you’ll get the following output:

This method was called prior to serializing the object!
This method was called after unserializing the object!

As you can see, the example above shows that each time the “save()” and “open()” methods are called — remember that these methods internally use the respective “serialize()/unserilalize() PHP functions –- the “__sleep()” and “__wakeup()” methods are also invoked, in this way displaying the messages shown above.

Even though the previous example may seem rather rudimentary, it serves to demonstrate how these magic methods are called in a transparent way by the PHP interpreter. However, this recently-acquired knowledge about how these methods work can be used for performing more useful tasks than displaying basic messages.

Keeping in mind the ability that PHP offers to call internally the mentioned methods, in the next section I’ll show you how to create objects that persist across several page requests without using any session mechanism. Go ahead and keep reading.

{mospagebreak title=Creating persisting objects}

Indeed, it’s feasible to use the “__sleep()” and “__wakeup()” functions that you learned in the previous section to do something useful. In this particular case, I’ll utilize the prior “ObjectSaver” class as the parent for deriving a child class that will expose a property that persists, that is, keeps its value across different page requests.

First, here is the source code that corresponds to the “ObjectSaver” class:

class ObjectSaver{
    var $objectFile;
    function ObjectSaver($objectFile=’defaultDir/objects.txt’){
        $this->objectFile=$objectFile;
        $this->save();
    }
    // save serialized object to file
    function save(){
        if(!$fp=fopen($this->objectFile,’w')){
            trigger_error(‘Error opening object
file’,E_USER_ERROR);
        }
        if(!fwrite($fp,serialize($this))){
            trigger_error(‘Error writing data to object
file’,E_USER_ERROR);
        }
        fclose($fp);
    }
    // fetch unserialized object from file
    function open(){
        if(!$obj=unserialize(file_get_contents($this-
>objectFile))){
            trigger_error(‘Error fetching object from
file’,E_USER_ERROR);
        }
        return $obj;
    }
    // define ‘__sleep()’ method
    function __sleep(){
        echo ‘This method was called prior to serializing the
object!<br />’;
        return array_keys(get_object_vars($this));       

    }
    // define ‘__wakeup()’ method
    function __wakeup(){
        echo ‘This method was called after unserializing the
object!<br />’;
    }
}

Now that I’ve listed the above class, the next step consists of deriving a child class from it, to create a persisting object. That said, here is the signature of the “CounterSaver” class, which, as you’ll see in a few moments, is capable of maintaining the value of its “counter” property:

/*
// ‘CounterSaver’ class extends ‘ObjectSaver’ class
// saves the value of ‘counter’ property to file and implements
persistence via
// the __sleep() and __wakeup() methods
*/
class CounterSaver extends ObjectSaver{
    var $objectFile;
    var $counterFile;
    var $counter;
    function CounterSaver($objectFile=’defaultDir/objects.txt’){
        $this->counterFile=’defaultDir/counter.txt’;
        $this->__wakeup();
        // call constructor of parent class
        parent::ObjectSaver($objectFile);   
    }
    // overwrite ‘__sleep()’ method
    function __sleep(){
        if(!$fp=fopen($this->counterFile,’w')){
            trigger_error(‘Error opening counter
file’,E_USER_ERROR);
        }
        if(!fwrite($fp,$this->counter)){
            trigger_error(‘Error writing data to counter
file’,E_USER_ERROR);
        }
        fclose($fp);
        return array_keys(get_object_vars($this));
    }
    // overwrite ‘__wakeup()’ method
    function __wakeup(){
        $this->counter=(!file_exists($this->counterFile))?
0:file_get_contents($this->counterFile);
    }
    // increment ‘counter’ property
    function incrementCounter(){
        $this->counter++;
    }
    // return counter property
    function getCounterValue(){
        return $this->counter;
    }
}

As you can see, the child “CounterSaver” class listed above overrides the parent “__sleep()” and “__wakeup()” methods. It stores and retrieves the value of its $counter property, which is appropriately saved to the “counter.txt” file. In this example I used a raw text file to save the property, but this can be easily changed to utilize a database table or even a simple cookie.

Now, the question that comes up is the following: how does an object spawned from the “CounterSaver” class implement some kind of persistence? All right, that’s fairly easy to demonstrate. Just take a look at the following script, which illustrates the concept of a “persisting” object:

$countSaver=&new CounterSaver();
// open object (calls the __wakeup method)
$countSaver->open();
// increment counter
$countSaver->incrementCounter();
// save object (calls the __sleep method)
$countSaver->save();
echo $countSaver->getCounterValue();

When the above script is executed, an initial value of 1 is first assigned to the $counter property. However, if the page is reloaded several times, this value will be appropriately incremented, certainly a fact that demonstrates that the value of this property “persists” across different page requests. As you saw, a persistent object has been created by using the “__sleep()” and “__wakeup()” methods that were overridden by the “CounterSaver” class.

As you can see, the logic of the previous script is very simple: after instantiating a new “CounterSaver” object, the “open()” method is called, which also triggers internally the “__wakeup()” method. Then, the $counter property is incremented and finally saved to the text file by “save(),” which additionally calls behind the scenes the “__wakeup()” method. See how these two magic functions can be used for creating persisting objects within an application? I hope you do!

To wrap up

Over this second article, I explored the magic “__sleep()” and “__wakeup()” functions, which are called automatically by the PHP interpreter when the “serialize()/unserialize()” functions are used inside a class. By providing a specific implementation for these functions I showed you how to create objects that maintain the value of their properties across several page requests, without the need to work with sessions.

Of course, persistence of objects is a broader subject, but in this tutorial I demonstrated how to build simple persisting objects via the PHP built-in mechanism. Not bad at all, right?

In the final part of this series, I’ll be covering object serialization with sessions, as well as storing serialized objects in MySQL database tables. See you in the last part!  

Google+ Comments

Google+ Comments