Home arrow PHP arrow Page 2 - Caching Result Sets in PHP: Porting the Code to PHP 5

One step prior to migrating: caching result sets with PHP 4 - PHP

In this part of the series, you will see in detail an updated version of each class that composes the caching system, for a correct implementation in PHP 5. Also, the “Cache” class will be modified to work with an array processor class that handles array operations. It should help refresh your memory of techniques related to object-oriented programming.

TABLE OF CONTENTS:
  1. Caching Result Sets in PHP: Porting the Code to PHP 5
  2. One step prior to migrating: caching result sets with PHP 4
  3. Taking advantage of an improved object model: updating the caching system to PHP 5
  4. Yet another modified class: updating the “Result” class
  5. The caching system’s core class: updating the “Cache” class
By: Alejandro Gervasio
Rating: starstarstarstarstar / 6
October 31, 2005

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

In order to take a quick look at the classes written in PHP 4, let’s first see their definitions and set up a short example. As you probably remember, I’ve developed a MySQL wrapping class that handles all of the operations for connecting to the server, running queries and obtaining result sets. Its source code was the following:

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){
                                               (!empty($value))?
$this->{$parameter}=$value:$this->isError('Invalid parameter
'.$parameter);
                                   }
                                   // connect to MySQL
                                   $this->connectDB();
                        }
                        else {
                                   $this->isError('No connection
parameters were provided');
                        }
            }
            // connect to MYSQL server and select database
            function connectDB(){
                        if(!$this->conId=mysql_connect($this-
>host,$this->user,$this->password)){
                                    $this->isError('Error
connecting to the server');
                        }
                        if(!mysql_select_db($this-
>database,$this->conId)){
                                    $this->isError('Error
selecting database');
                        }
            }
            // perform query
            function query($query){
                        if(!$this->result=mysql_query
($query,$this->conId)){
                                   $this->isError('Error
performing query '.$query);
                        }
                        // return new Result object
                        return new Result($this,$this->result);
            }
            // display errors
            function isError($errorMsg){
                       trigger_error($errorMsg.' '.mysql_error
());
                       exit();
            }
}

 

Then, the next class involved to make the caching system work was the “Result” class, which is aimed specifically at managing MySQL result sets. Its corresponding source code was defined in the following way:

class Result{
            var $mysql; // instance of MySQL object
            var $result; // result set
            // constructor
            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)){
                                   $this->mysql->isError('Error
counting rows');
                        }
                        return $rows;
            }
            // count affected rows
            function countAffectedRows(){
                        if(!$rows=mysql_affected_rows($this-
>mysql->conId)){
                                   $this->mysql->isError('Error
counting affected rows');
                        }
                        return $rows;
            }
            // get ID from last inserted row
            function getInsertID(){
                        if(!$id=mysql_insert_id($this->mysql-
>conId)){
                                   $this->mysql->isError('Error
getting ID');
                        }
                        return $id;
            }
            // seek row
            function seekRow($row=0){
                        if(!mysql_data_seek($this->result,$row)){
                                   $this->mysql->isError('Error
seeking data');
                        }
            }
}

Finally, the core class for handling the logic of the caching system was the already familiar “Cache” class. It was defined like this:

class Cache{
            var $mysql;  // instance of MySQL object
            var $result; // instance of Result object
            var $expiry; // cache expire time in seconds
            var $cacheFile; // cache file
            var $data; // result set array
            // constructor
            function Cache
(&$mysql,$expiry=86400,$cacheFile='default_cache.txt'){
                        $this->mysql=&$mysql;
                        (is_int($expiry)&&$expiry>0)?$this-
>expiry=$expiry:$this->mysql->isError('Expire time must be a
positive integer');
                        $this->cacheFile=$cacheFile;
                        $this->data=array();
            }
            // if cache is valid, perform query and return a
result set. Otherwise, get results from cache file
            function query($query){
                        // check if query starts with SELECT
                        if(!preg_match("/^SELECT/",$query)){
                                   $this->mysql->isError('Invalid
query. Must start with SELECT');
                        }
                        if(!$this->isValid()){
                                   // read from MySQL
                                   $this->result=$this->mysql-
>query($query);
                                   $this->data=$this->write();
                        }
                        else {
                                   // read from cache file
                                   $this->data=$this->read();
                        }
            }
            // write cache file
            function write(){
                        if(!$fp=fopen($this->cacheFile,'w')){
                                   $this->mysql->isError('Error
opening cache file');
                        }
                        if(!flock($fp,LOCK_EX)){
                                   $this->mysql->isError('Unable
to lock cache file');
                        }
                        while($row=$this->result->fetchRow()){
                                   $content[]=$row;
                        }
                        if(!fwrite($fp,serialize($content))){
                                   $this->mysql->isError('Error
writing to cache file');
                        }
                        flock($fp,LOCK_UN);
                        fclose($fp);
                        unset($fp,$row);
                        return $content;
            }
            // read cache file
            function read(){
                        if(!$content=unserialize
(file_get_contents($this->cacheFile))){
                                   $this->mysql->isError('Error
reading from cache file');
                        }
                        return $content;
            }
            // determine cache validity based on a time expiry
trigger
            function isValid(){
                        if(file_exists($this->cacheFile)
&&filemtime($this->cacheFile)>(time()-$this->expiry)){
                                   return true;
                        }
                        return false;
            }
            // fetch row
            function fetchRow(){
                        if(!$row=current($this->data)){
                                   return false;
                        }
                        next($this->data);
                        return $row;
            }
            // fetch all rows
            function fetchAll(){
                        if(count($this->data)<1){
                                   $this->mysql->isError('Error
accessing cache data');
                        }
                        return $this->data;
            }
            // count rows
            function countRows(){
                        if(!$rows=count($this->data)){
                                   $this->mysql->isError('Error
counting cache rows');
                        }
                        return $rows;
            }
}

Okay, having listed the source code for each class, we’re able to implement an example that shows up the capabilities of the caching system, within an object-oriented scenario. Here it is:

// connect to MySQL
$db=new MySQL(array('host'=>'host','user'=>'user','password'=>'password',
'database'=>'databasename'));
// instantiate a new Cache object, valid for 24 hours (time
expiry triggered caching)
$cache=&new Cache($db,86400);
// perform query and store results in cache file
// if cache is not valid, force a new cache generation
$cache->query('SELECT * FROM products');
// loop over rows and display results
while($row=$cache->fetchRow()){
            echo $row['name'].'&nbsp;'.$row
['description'].'<br />';
}
// count rows
echo ‘Total number of products ’ .$cache->countRows();

The above example clearly illustrates how to implement the three previous classes, by putting them together to set up the caching mechanism. In this particular case, I’ve decided to cache the data coming from a  “products” database table during a period of 24 hours. Also, the example shows the usage of the “fetchtRows()” and “countRows()” methods, for displaying data and counting rows respectively.

All right, since we’ve tested the capabilities of this caching solution developed in PHP 4, it’s recommended that we go one step further and explain how a similar system may be programmed in PHP 5. Due to the fact that PHP 5 presents some differences, most of them aimed at improving the Object Model, the advantages and benefits are significant compared to the version implemented in PHP 4.

Therefore, let’s cross the barrier between language versions and update the caching system to PHP 5.



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: