HomePHP Page 4 - Using the Sleep and Wakeup Functions to Serialize Objects in PHP
Creating persisting objects - 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.
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!