Working with MySQL and Sessions to Serialize Objects in PHP

If you’re interested in learning how to combine objects, sessions and MySQL, this is the article that you’ve been waiting for. It’s the final part of the series “Serializing objects in PHP.” In three parts, this series goes through the fundamentals of serializing objects in PHP applications, and explores some advanced topics with regard to this subject, including the use of the magic “__sleep()” and “__wakeup()” functions, and the manipulation of serialized objects inside of MySQL tables.

Introduction

If you’ve been reading the previous tutorials, then you’ve hopefully learned the basics of how to serialize/unserialize objects in PHP, as well as how to use the combination of “__sleep()” and “__wakeup()” functions to create objects that are capable of maintaining their state across different web page requests. As you’ll probably recall, these types of objects are called persisting objects, and in general terms, are constructed without the need to use the PHP built-in session handling mechanism.

Aside from the practical implementation of serialization for building persisting objects, it should be noted that there’s plenty of room to use serialized objects in Web applications, either as part of more advanced programming approaches, or in order to achieve something as simple as storing objects in text files and cookies. Once you’ve mastered the concepts behind object serialization, you can go ahead and develop several applications (an object caching system, to cite an illustrative example), which use serialization for achieving some basic tasks.

Provided that you’ve already grasped the key concepts about object serialization, in addition to implementing some advanced features, such as the ones I mentioned right at the beginning of this article, in this final installment of the series, I’ll show you some examples of how to work with objects and sessions. I’ll also show you how to use MySQL tables to keep your objects safe and healthy.

So, are you interested in learning how to combine objects, sessions and MySQL? Let’s start exploring this powerful combination.

{mospagebreak title=The basics of automated object serialization: using objects and sessions}

Registering objects as session data is really a straightforward process, since it doesn’t differ too much from registering other data types. However, there’s a couple of things that must be taken into account when using objects and sessions.

First off, when an object is registered in a session, it will be automatically serialized during the registration process, and in turn unserialized if the object is eventually stored in a new variable. As you can see, the complete serialize/unserialize sequence is entirely handled by the PHP interpreter, so in theory you shouldn’t worry about how your objects are handled behind the scenes.

Nevertheless, the second point to consider when working with objects and sessions is that all the pages where an object will be handled as session data (including registration, manipulation, deregistration, and so on)  must include the definition of the class (or classes) from which the object in question is spawned.

To clarify the concepts that I deployed before, I start with a simple example – an object that will be registered during a regular session. Here is the corresponding code:

// define sample ‘DataSaver’ class
class DataSaver{
    var $data;
    var $dataFile;
    function DataSaver($data,$dataFile=’defaultDir/data.txt’){
        if(!is_string($data)){
            trigger_error(‘Invalid data type’,E_USER_ERROR);
        }
        $this->data=$data;
        $this->dataFile=$dataFile;
    }
    // save data to file
    function save(){
        if(!$fp=fopen($this->dataFile,’w’)){
            trigger_error(‘Error opening data
file’,E_USER_ERROR);
        }
        fwrite($fp,$this->data);
        fclose($fp);
    }
    // fetch data from file
    function fetch(){
        if(!$contents=file_get_contents($this->dataFile)){
            trigger_error(‘Error opening data
file’,E_USER_ERROR);
        }
        return $contents;
    }
}
// instantiate ‘DataSaver’ object
$dataSaver=&new DataSaver(‘This object will be serialized and
saved as session data.’);
// register ‘DataSaver’ objects as session data
session_start();
$_SESSION['object']= $dataSaver;

In the above example, you can see that I included the definition of the sample “DataSaver” class before instantiating an object from it, and naturally prior to registering this object in a session variable.

Now, I’ll suppose that a “$dataSaver” object needs to be used on a different page, after being registered during the prior session. Considering this situation, this sample page should be coded as follows:

// define sample ‘DataSaver’ class
class DataSaver{
    var $data;
    var $dataFile;
    function DataSaver($data,$dataFile=’defaultDir/data.txt’){
        if(!is_string($data)){
            trigger_error(‘Invalid data type’,E_USER_ERROR);
        }
        $this->data=$data;
        $this->dataFile=$dataFile;
    }
    // save data to file
    function save(){
        if(!$fp=fopen($this->dataFile,’w’)){
            trigger_error(‘Error opening data
file’,E_USER_ERROR);
        }
        fwrite($fp,$this->data);
        fclose($fp);
    }
    // fetch data from file
    function fetch(){
        if(!$contents=file_get_contents($this->dataFile)){
            trigger_error(‘Error opening data
file’,E_USER_ERROR);
        }
        return $contents;
    }
}
session_start();
$dataSaver=$_SESSION['object'];
echo $dataSaver->fetch();

As shown above, I included the complete definition of the “DataSaver” class before any attempt to resume the previous session and restore the respective object. Once this has been successfully done, the “$dataSaver” object is restored and its “fetch()” method is called appropriately. The output of the previous script is the following:

This object will be serialized and saved as session data.

As you can see, if you’re careful enough and include the corresponding class definitions of all the objects you’ll be working with, you shouldn’t have any problems combining objects and sessions.

All right, in the previous example you learned how to register objects in session variables, but the entire registration process was handled procedurally. Therefore, in the next section I’ll restructure the code sample you saw before, and create a simple session handling class. It will have the ability to register, fetch and deregister objects. Please go ahead and read the next few lines.

{mospagebreak title=Combining objects and sessions: defining a session handling class}

In order to restructure the example I showed you in the previous section, I’ll simply define a session handling class, in such a way that all the tasks for registering, retrieving and deregistering objects will be handled from inside this class. Here is the signature of the “SessionHandler” class:

class SessionHandler{
    function SessionHandler(){
        session_start();
    }
    // register object as session data
    function registerObject($obj,$objName=’defaultObject’){
        if(!is_object($obj)){
            trigger_error($obj.’ must be an
object!’,E_USER_ERROR);
        }
        if($objName==”){
            trigger_error(‘Invalid object name.’,E_USER_ERROR);
        }
        $_SESSION[$objName]=$obj;
    }
    // deregister object from session data
    function unregisterObject($objName=’defaultObject’){
        if(!$_SESSION[$objName]){
            trigger_error(‘Invalid object name.’,E_USER_ERROR);
        }
        unset($_SESSION[$objName]);
    }
    // retrieve session object
    function getObject($objName=’defaultObject’){
        if(!$_SESSION[$objName]){
            trigger_error(‘Invalid object name.’,E_USER_ERROR);
        }
        return $_SESSION[$objName];
    }
}

As you can see, the session handling class listed above exposes a few simple methods, handy for registering objects in session variables, as well as for fetching and deregistering them. Based on the functionality provided by this brand new class, the example shown in the previous section can be rewritten as follows:

class DataSaver{
    var $data;
    var $dataFile;
    function DataSaver($data,$dataFile=’defaultDir/data.txt’){
        if(!is_string($data)){
            trigger_error(‘Invalid data type’,E_USER_ERROR);
        }
        $this->data=$data;
        $this->dataFile=$dataFile;
    }
    // save data to file
    function save(){
        if(!$fp=fopen($this->dataFile,’w’)){
            trigger_error(‘Error opening data
file’,E_USER_ERROR);
        }
        fwrite($fp,$this->data);
        fclose($fp);
    }
    // fetch data from file
    function fetch(){
        if(!$contents=file_get_contents($this->dataFile)){
            trigger_error(‘Error opening data file’,E_USER_ERROR);
        }
        return $contents;
    }
}

// use ‘SessionHandler’ class to register and deregister objects
$dataSaver=&new DataSaver(‘This object will be serialized and
saved as session data.’);
// save string to file
$dataSaver->save();
// instantiate ‘SessionHandler’ object
$sessHand=&new SessionHandler();
// register session object
$sessHand->registerObject($dataSaver,’datasaver’);
// deregister object
$sessHand->unregisterObject(‘datasaver’);
// retrieve object after deregistering it (triggers a fatal
error)
$sessHand->getObject(‘datasaver’);

In this example, I registered a “$dataSaver” object on a session variable by using the “registerObject()” method that belongs to the “SessionHandler” class. Similarly, the referenced object can be retrieved or deregistered in turn, as shown at the end of the script.

If you’re planning to use your registered objects across different pages during a particular session (as is usually done), again you must include, within all the files, the definition of all the classes that correspond to the objects that will be used.

With reference to the previous example, say you want to restore and use a “DataSaver” object in a different page. This document should be coded like this:

// define sample ‘DataSaver’ class
class DataSaver{
    var $data;
    var $dataFile;
    function DataSaver($data,$dataFile=’defaultDir/data.txt’){
        if(!is_string($data)){
            trigger_error(‘Invalid data type’,E_USER_ERROR);
        }
        $this->data=$data;
        $this->dataFile=$dataFile;
    }
    // save data to file
    function save(){
        if(!$fp=fopen($this->dataFile,’w’)){
            trigger_error(‘Error opening data
file’,E_USER_ERROR);
        }
        fwrite($fp,$this->data);
        fclose($fp);
    }
    // fetch data from file
    function fetch(){
        if(!$contents=file_get_contents($this->dataFile)){
            trigger_error(‘Error opening data
file’,E_USER_ERROR);
        }
        return $contents;
    }
}
// define ‘SessionHandler’ class
class SessionHandler{
    function SessionHandler(){
        session_start();
    }
    // register objects as session data
    function registerObject($obj,$objName=’defaultObject’){
        if(!is_object($obj)){
            trigger_error($obj.’ must be an
object!’,E_USER_ERROR);
        }
        if($objName==”){
            trigger_error(‘Invalid object name.’,E_USER_ERROR);
        }
        $_SESSION[$objName]=$obj;
    }
    // deregister object from session data
    function unregisterObject($objName=’defaultObject’){
        if(!$_SESSION[$objName]){
            trigger_error(‘Invalid object name.’,E_USER_ERROR);
        }
        unset($_SESSION[$objName]);
    }
    // retrieve session object
    function getObject($objName=’defaultObject’){
        if(!$_SESSION[$objName]){
            trigger_error(‘Invalid object name.’,E_USER_ERROR);
        }
        return $_SESSION[$objName];
    }
}
// instantiate ‘SessionHandler’ object
$sessHand=&new SessionHandler();
// retrieve registered session object
$dataSaver=$sessHand->getObject(‘datasaver’);
// call ‘fetch()’ method
echo $dataSaver->fetch();

In this specific example, I explicitly included the definition of all the classes that will be used at a later time, but obviously this should be done by using a “require_once()” statement, in order to simplify the script’s source code. Also, notice how the “$dataSaver” object is properly retrieved via the “getObject()” method that belongs to the “SessionHandler” class. Simple and instructive, right?

At this stage, I think you’ve already grasped the basics of working with objects and sessions, which is an important part of object serialization, since this process is performed internally by the PHP interpreter. From this point onward, you can develop full-featured applications that will smartly combine your objects and sessions.

Finally, the conclusion of this article will rest on setting up a practical example that will demonstrate how to store serialized objects in MySQL tables, instead of using conventional BLOBs.

The last section of the article explains how to achieve this, therefore click on the link below to learn more on this topic.

{mospagebreak title=Another implementation of object serialization: saving objects to MySQL tables}

As I said before, the last example I’m going to show you illustrates the entire process for storing serialized objects in a MySQL table. To begin with, I’ll define a simple “objects” database table, composed of  “id” and “users” fields, which will house the IDs of stored objects and their serialized structure. Here is the SQL statement that creates this table:

CREATE TABLE objects (
id INT(4) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
users TEXT NOT NULL
);

As you can see, the table for storing serialized objects is fairly simple, thus now I’m going to build a basic “User” class, which will store some data about fictional people, such as Name, Postal Address and Email. The signature of the class looks like this:

// define ‘User’ class
class User{
    var $name;
    var $address;
    var $email;
    function User($userData=array()){
        if(!is_array($userData)){
            trigger_error(‘User data must be an
array!’,E_USER_ERROR);
        }
        foreach($userData as $property=>$value){
            if($property==”||$value==”){
                trigger_error(‘Invalid values for user
data!’,E_USER_ERROR);
            }
            $this->{$property}=$value;
        }
    }
    // obtain user name
    function getName(){
        return $this->name;
    }
    // obtain user address
    function getAddress(){
        return $this->address;
    }
    // obtain user email
    function getEmail(){
        return $this->email;
    }
}

 

That’s it. Now I defined the corresponding “User” class, which will serve to spawn as many objects as required, and after being serialized, these objects will be stored in the “objects” sample table.

There’s still one more thing that I wish to do before proceeding to store objects in a MySQL table: I’ll create an object serializing class, in order to handle the complete serialize/unserialize process by using its interface. The source code of this class, which I called “ObjectSerializer”, is shown below:

class ObjectSerializer{
    function ObjectSerializer(){}
    function getSerializedObj($obj){
        if(!is_object($obj)){
            trigger_error($obj.’input parameter must be an
object!’,E_USER_ERROR);
        }
        return serialize($obj);
    }
    function getUnserializedObj($data){
        if(!is_string($data)){
            trigger_error($data. ‘must be a
string!’,E_USER_ERROR);
        }
        return unserialize($data);
    }
}          

In this case, the above class was defined as a simple wrapper for the pair of “serialize()/unserialize()” PHP functions, so it does not require much discussion about how it works. Given that, the next step consists of populating the “objects” table with some users, so first I’ll proceed to create them, like this:

// instantiate some ‘User’ objects
$usr1=&new User(array(‘name’=>’John Doe’,’address’=>’5456
Protocol Avenue MA’,’email’=>’john@domain.com’));
$usr2=&new User(array(‘name’=>’Susan Smith’,’address’=>’12345 Web
Boulevard CA’,’email’=>’susan@domain.com’));
$usr3=&new User(array(‘name’=>’Jeff Williams’,’address’=>’154321
Hyperlink Road NV’,’email’=>’jeff@domain.com’));
$usr4=&new User(array(‘name’=>’Bridget Lopez’,’address’=>’13579
Socket Street NY’,’email’=>’bridget@domain.com’));

All right, now that some fictional users have been created, it’s time to serialize them and store them in the “objects” database table. To do this, I’ll use a couple of MySQL wrapper classes that will be listed at the end of the example. Here is how the entire set of “Users” objects are stored in the corresponding table:

// connect to MySQL
$db=&new MySQL(array(‘host’=>’host’,’user’=>’user’,’password’=>’pass’,
‘database’=>’database’));
// instantiate ‘ObjectSerializer’ object
$objSer=&new ObjectSerializer();
// insert objects into database table
$db->query(“INSERT INTO objects (id,users) VALUES
(NULL,'”.$objSer->getSerializedObj($usr1).”‘)”);
$db->query(“INSERT INTO objects (id,users) VALUES
(NULL,'”.$objSer->getSerializedObj($usr2).”‘)”);
$db->query(“INSERT INTO objects (id,users) VALUES
(NULL,'”.$objSer->getSerializedObj($usr3).”‘)”);
$db->query(“INSERT INTO objects (id,users) VALUES
(NULL,'”.$objSer->getSerializedObj($usr4).”‘)”);

As you can see, the above script first connects to MySQL, then instantiates a new “ObjectSerializer” object, and finally inserts all the serialized “User” objects into the sample “objects” database table. Definitely, you’ll agree with me that this step is simple and comprehensive.

Once the respective users have been stored, I’m going to reverse the process and fetch the objects from the respective table, so I’m able to use their methods to display the information attached to them. Take a look at the piece of code below that precisely demonstrates how the objects are restored:

// restore objects from database table
$result=$db->query(“SELECT * from objects”);
while($row=$result->fetchRow()){
    $obj=$objSer->getUnserializedObj($row['users']);
    echo ‘ID: ‘. $row['id'].’ Name: ‘.$obj->getName().’ Postal
Address: ‘.$obj->getAddress().’ Email: ‘.$obj->getEmail().'<br />';
}

In this case, objects are first fetched from the database table by using a regular SELECT statement, and then unserialized by the “getUnserializedObj()” method. Finally, the data associated with each user is displayed by calling each of the corresponding getters.

Of course, below I listed the output generated by the previous example:

ID: 1 Name: John Doe Postal Address: 5456 Protocol Avenue MA Email: john@domain.com
ID: 2 Name: Susan Smith Postal Address: 12345 Web Boulevard CA Email: susan@domain.com
ID: 3 Name: Jeff Williams Postal Address: 154321 Hyperlink Road NV Email: jeff@domain.com
ID: 4 Name: Bridget Lopez Postal Address: 13579 Socket Street NY Email: bridget@domain.com

Even when you’re usually storing your binary objects in BLOB table fields, the approach that I just showed you before can be considered a useful alternative for saving objects as plain strings.

{mospagebreak title=The complete list of classes for the example}

Finally, for the sake of completeness, below I listed all the classes that I used for constructing the previous example:

// define ‘User’ class
class User{
    var $name;
    var $address;
    var $email;
    function User($userData=array()){
        if(!is_array($userData)){
            trigger_error(‘User data must be an
array!’,E_USER_ERROR);
        }
        foreach($userData as $property=>$value){
            if($property==”||$value==”){
                trigger_error(‘Invalid values for user
data!’,E_USER_ERROR);
            }
            $this->{$property}=$value;
        }
    }
    // obtain user name
    function getName(){
        return $this->name;
    }
    // obtain user address
    function getAddress(){
        return $this->address;
    }
    // obtain user email
    function getEmail(){
        return $this->email;
    }
}
// define ‘ObjectSerializer’ class
class ObjectSerializer{
    function ObjectSerializer(){}
    function getSerializedObj($obj){
        if(!is_object($obj)){
            trigger_error($obj.’input parameter must be an
object!’,E_USER_ERROR);
        }
        return serialize($obj);
    }
    function getUnserializedObj($data){
        if(!is_string($data)){
            trigger_error($data. ‘must be a
string!’,E_USER_ERROR);
        }
        return unserialize($data);
    }
}
// define ‘MySQL’ class
class MySQL {
    var $conId; // connection identifier
    var $host; // MySQL host
    var $user; // MySQL username
    var $password; // MySQL password
    var $database; // MySQL database
    // constructor
    function MySQL($options=array()){
        // validate incoming parameters
        if(count($options)>0){
            foreach($options as $parameter=>$value){
                if(empty($value)){
                    trigger_error(‘Invalid parameter
‘.$parameter,E_USER_ERROR);
                }
                $this->{$parameter}=$value;
            }
            // connect to MySQL
            $this->connectDB();
        }
        else {
            trigger_error(‘No connection parameters were
provided’,E_USER_ERROR);
        }
    }
    // connect to MYSQL server and select database
    function connectDB(){
        if(!$this->conId=mysql_connect($this->host,$this-
>user,$this->password)){
            trigger_error(‘Error connecting to the
server’,E_USER_ERROR);
        }
        if(!mysql_select_db($this->database,$this->conId)){
            trigger_error(‘Error selecting
database’,E_USER_ERROR);
        }
    }
    // perform query
    function query($query){
        if(!$this->result=mysql_query($query,$this->conId)){
            trigger_error(‘Error performing query
‘.$query,E_USER_ERROR);
        }
        // return new Result object
        return new Result($this,$this->result); 
    }
}
// define ‘Result’ class
class Result {
    var $mysql; // instance of MySQL object
    var $result; // result set
    function Result(&$mysql,$result){
        $this->mysql=&$mysql;
        $this->result=$result;
    }
    // fetch row
    function fetchRow(){
        return mysql_fetch_array($this->result,MYSQL_ASSOC);
    }
    // count rows
    function countRows(){
        if(!$rows=mysql_num_rows($this->result)){
            return false;
        }
        return $rows;
    }
    // count affected rows
    function countAffectedRows(){
        if(!$rows=mysql_affected_rows($this->mysql->conId)){
            trigger_error(‘Error counting affected
rows’,E_USER_ERROR);
        }
        return $rows;
    }
    // get ID from last inserted row
    function getInsertID(){
        if(!$id=mysql_insert_id($this->mysql->conId)){
            trigger_error(‘Error getting ID’,E_USER_ERROR);
        }
        return $id;
    }
    // seek row
    function seekRow($row=0){
        if(!mysql_data_seek($this->result,$row)){
            trigger_error(‘Error seeking data’,E_USER_ERROR);
        }
    }
    function getQueryResource(){
        return $this->result;
    }
}

To wrap up

We’re done now. Over this series, I covered not only the fundamentals of object serialization in PHP, but also some advanced topics, such as the implementation of the magic “__sleep()” and “__wakeup()” functions, and the usage of objects in sessions. Finally, I completed the series by demonstrating how to store serialized objects in MySQL tables, which makes me believe that you have enough code to keep you experimenting for many hours. As usual, see you in the next PHP tutorial!

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan