Archive

Posts Tagged ‘save’

A Simple Introduction To Zend_Cache

April 2nd, 2009 No comments

The Zend_Cache class is part of the Zend Framework and is used (as its name suggests) to cache things. This can be anything from the front end browser output to the outcome of a complex calculation or even the results of database queries. Zend_Cache is an enormous topic, not just how the class works, but what the best practices are for caching.

The best place to start with caching is one of the simpler topics of caching database queries. Normally, a call to a database table in Zend Framework might be done like this.

$houses    = new Houses();
$result      = $houses->fetchAll();

The result would then be processed. To use Zend_Cache instead of calling the database we first need to set up our Zend_Cache object so that we can use it. To do this we need to call the Zend_Cache static function factory() with a few parameters, which will give us a cache object. Here is a typical example.

$query_cache = Zend_Cache::factory('Core', 'File', $frontendoptions, $backendoptions);

The parameters are as follows:

  • 'Core' – This can be a number of different options which dictate what sort of things are cached on the frontend, the value here is mapped to a class. In this case the class is Zend_Cache_Core, but other classes are mapped to Zend_Cache_Frontend_*. The Zend_Cache_Core class is best used for database calls because there is no specific frontend class that deals with database calls.
  • 'File' – This indicates where the cache is to be stored in the backend. Again this value maps to a class, in this case Zend_Cache_Backend_File. In most cases the Zend_Cache_Backend_File class is the simplest and easiest option to use.
  • $frontendoptions – This is an array of options that relates to the frontend class you have chosen.
  • $backendoptions – This is an array of options that relates to the backend class you have chosen.

The following code sets up an instance of Zend_Cache using some common parameters. Note that different frontend and backend classes have a different set of parameters, but the parameters used below are for the Core frontend and the File backend. The APPLICATION_PATH constant just points to our application folder.

$frontendoptions = array(
    'lifetime' => 60 * 5, // 5minutes
    'automatic_serialization'=>true
);
$backendoptions = array(
    'cache_dir'=> APPLICATION_PATH . '/cache/',
    'file_name_prefix' => 'zend_cache_query',
    'hashed_directory_level' => 2
);
$query_cache = Zend_Cache::factory('Core', 'File', $frontendoptions, $backendoptions);

Here is an explanation of the frontend options used.

  • lifetime – This is self explanatory. If the cache created is greater than the number of seconds for this parameter then the cache is deleted. This can be set to null if we wan’t the cache to last forever.
  • automatic_serialization – If set to true this will automatically serialise the cache data. This allows you to store complex data like objects and arrays. If you are storing a numeric value or text string only then you can set this to false.

Here is an explanation of the backend options used.

  • cache_dir – This is the directory that the cache is to be kept in. The default to this is /tmp/ but it is best to keep the cache within the application folder so that you can manage the files manually if need be.
  • file_name_prefix – This sets the start of the filename to be used, because I want to cache database queries I have selected zend_cache_query as my prefix.
  • hashed_directory_level – Some file systems have great difficulty handling lots of files in a single directory. This option splits the cache into different levels or directories. The default is 0, but for this example I have selected 2. This means that our cache files will be stored inside 2 levels of directories.

To load a cache we use the load() function. This function takes a parameter that identifies the cache, but because we are getting all data from the houses table we don’t need to worry too much about this. If there is no cache with that name present then the function returns false. If this occurs we run our normal database query but in each case the $result variable will contain our data.

if ( !($result = $query_cache->load('allhouses')) ) {
    $houses    = new Houses();
    $result      = $houses->fetchAll();
    $query_cache->save($result, 'allhouses');
}

Once we have run the normal query we save the result to the cache using the save() function. This contains the data we want to save in the first parameter and the same cache name as the load() function in the second parameter. The next time the page is loaded the cache is loaded instead of calling the database.

We can also cache single data rows in the same way by using a unique identifier for our cache name. Assuming that have our house id we can do the following:

$cacheName = 'house'.$id;
if ( !($result = $query_cache->load($cacheName )) ) {
    $houses    = new Houses();
    $result      = $houses->fetchRow($houses->select()->where('id = ?', $id));
    $query_cache->save($result, $cacheName );
}

Note that if you want to do anything more than display the results of the query then you will need to access the database directly. It is not possible to interact with a database through the cached object.

Save Browser Output To A File With PHP Output Buffering Functions

March 19th, 2008 2 comments

The PHP output buffering functions provide a handy way of intercepting the contents of the buffer before it is sent to the browser. The output is whatever is sent to the browser whenever you print something off. PHP allows you to capture this output in a buffer before it is sent to the browser.

Output buffering is controlled by two mechanisms. The first is through the php.ini directive output_buffering, which is usually set to off. It can be turned on by setting this to either on, or the number of bytes that the buffer can take up. When this byte allocation is full the output is sent to the browser.

The second mechanism is through the use of the ob_start() function, which turns on output buffering for the script it is being run on. If output buffering has been set in the php.ini file then this isn’t needed, but if it has been set to ‘off’ then you will get some errors if you try to do anything with the buffer. To start output buffering just call the ob_start() function.

ob_start();

Whatever you try to print off now will not be output to the browser until the end of the script. To explicitly push the output to the browser you can call the ob_flush() function.

echo 'test';
ob_flush();

You can turn off output buffering at any time by calling either ob_end_clean() or ob_end_flush(). ob_end_clean() will turn off the top most buffer (you can have more than one) and discard the contents. ob_end_flush() will output the contents of the top most buffer then turn it off. Here is an easy way to use ob_end_flush() to flush and turn off all available output buffers and output their contents.

while (@ob_end_flush());

You can get the contents of the output buffer at any time (as long as you haven’t turned it off) by calling the ob_get_contents() function. This returns the current buffer contents. Here is an example of it in action.

<?php
ob_start();
echo 'test ';
?>
some more text
<?php
$out = ob_get_contents();
ob_end_flush();
// $out now contains 'test some more text'.
?>

The ob_flush() function will empty the current output buffer and send this to the browser. So it is important to call this function after you have got the contents of the buffer. If you call it before you try to get the buffer contents there will be nothing there.

Using the ob_get_contents() function is how you can output text to both a file and the browser. The following example will write some text to the browser and also store this text in a variable that is written to a file at the end of the script. The file is given the current time stamp as a name.

$out = '';
ob_start();
echo 'test';
$out .= ob_get_contents();
ob_flush();
echo ' some more text to add to the buffer';
$out .= ob_get_contents();
ob_end_flush();
// check that something was actually written to the buffer
if(strlen($out)>0){
 $file = 'debug/'.time().'.html';
 touch($file);
 $fh = fopen($file,'w');
 fwrite($fh,$out);
 fclose($fh);
}

The ob_start() function can be called without any parameters, but you can supply the name of a function that will be used to pass the contents of the buffer through before it is sent to the browser. Using this mechanism is slightly easier as it can be easily removed from any script. The call back function must have a single string parameter, which is the contents of the buffer, and must return a string, preferably the contents of the buffer.

function bufferCallBack($buffer){
// check that something was actually written to the buffer
 if(strlen($out)>0){
  $file = 'debug/'.time().'.html';
  touch($file);
  $fh = fopen($file,'w');
  fwrite($fh,$out);
  fclose($fh);
 }
 return $buffer;
}
 
ob_start('bufferCallBack');
echo 'test';
echo ' some more text to add to the buffer';
ob_end_flush();

Be warned that the use of output buffering can lead to the apparent slowdown of your website due to everything being generated server side before being sent to the client.