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