| Frames | Modems | Help | Home Page | Chipsets | Search | No Frames |
| Diary Entries | See also Site Info & Diary. | |
| 28 March 2004 | Documenting the php PEAR Cache_Lite Class... | |
The sob story: all I wanted to do was write a little routine to let me see a graph of the last 100 days hits on my sites. That’s not much to ask, is it? Should only take a day or so. The MySQL routines for this are a bit slow, but, using caching, it might be possible to put it up as a public feature. As soon as I went to look for the documentation on the Date and Time class (there wasn’t any) I knew that this was going to be a grind. This page seeks to document (below) one of the un-documented Classes within PEAR--the “PHP Extension and Application Repository”, one of the hidden extras of PHP--namely the Cache_Lite Class. [4 Apr update: caching has been introduced to the Search pages. Early results are encouraging; one page was reduced from 3.36 to 0.11 secs to produce.] Info on PEAR, including installation, can be found on my site as part of the Date class documents. I do not have the time to do a full job here, but will attempt to at least list all the functions of the Class and to give any specifics as I find & use them. |
||
Cache_Lite describes itself as a “Fast, light and safe Cache Class”. It gives itself 3 main goals:
There is a brief tutorial translated from the original French, and a DevShed article (broken when I tried it). WebReference has a good general article on caching, which includes specifics on Cache_Lite. There is also a page of PEAR API Documentation which uses phpDocumentor to list all Cache_Lite Classes & functions. In the course of researching all this I also came across an excellent--though rather long--article on optimising PHP. Because of all the above, this will be documentation-Lite, using my own site(s) as a touchstone (as a side comment, modem-help.com can also be accessed via modem-help.uklinux.net (not any more); modem-help.freeserve.co.uk leads to the same page, and modem-help.co.uk (used to) encourage you to go to the .com site; this proliferation of urls is due to the historic development of these sites - more info is on the compression page). One of the display goals for modem-help.com is to get each php page script to complete in less than one-tenth of a second. The biggest successes in this effort came through focussing on SQL statements (the site uses MySQL 3.23.58-log). Some statements stubbornly refused to be optimised any further yet were very slow. These die-hards were ideal candidates for a Cache routine, and implementing such a routine became one of my mid-term goals. [Another side-comment: I was surprised to find that a Limit clause within the SQL did not seem to speed it up. Indeed, returning all 30,000 lines seemed to take less time than returning the last 10. Strange.] Cache_Lite offers 3 kinds of caching:
...and each one can be done on a global or a group basis, on disk or in memory (this latter is described as “beta quality”). Caching requires a bit of pre-thought before you begin to use it. In my case, the routine collects an array of 100 days-worth of hits. If in the cache already only today’s hits need collecting, whilst at midnight the cache needs refreshing with a new array. Eventually, I will probably use Function.php, but for now will use Lite.php. Written as pseudo-code it looks like this: <?php
require_once 'Cache/Lite.php';
require_once 'Date.php';
$oldDay = $today = new Date();
$oldDay->subtractSeconds( 100 * 86400 ); // 100 days
$today_query_com = "(sql statement)"; // ~0.0100 sec Domain: modem-help.com
$today_query_uk = "(sql statement)"; // ~0.1724 sec Domains: Freeserve + .co.uk
$full_query_com = "(sql statement)"; // ~0.4409 sec
$full_query_uk = "(sql statement)"; // ~0.4687 sec
$id = 'hits'; // timing begins (code not shown)
$options = array(
'automaticSerialization' => TRUE,
'lifeTime' => 86400 // one day max
);
$cache = new Cache_Lite( $options );
if ( $hits = $hitsCache->get( $id ) { // cache hit
$cacheDay = new Date( $cache->lastModified() );
$todayDOW = $today->getDayOfWeek();
$cacheDOW = $cacheDay->getDayOfWeek();
}
if ( $hits && $todayDOW == $cacheDOW ) { // cache hit + same day
// only need to refresh today`s hits
$r = mysql_query( $today_query_com );
while( list(...) = mysql_fetch_row( $r ) ) $hits[date][domain] = $visit;
$r = mysql_query( $today_query_uk );
while( list(...) = mysql_fetch_row( $r ) ) $hits[date][domain] = $visit;
} else { // cache miss or not same day
// need to do full query + save in cache
$r = mysql_query( $full_query_com );
while( list(...) = mysql_fetch_row( $r ) ) $hits[date][domain] = $visit;
$r = mysql_query( $full_query_uk );
while( list(...) = mysql_fetch_row( $r ) ) $hits[date][domain] = $visit;
$cache->save( $hits );
} // timing ends
?>
Early timing tests are 0.18 secs / 0.89 secs (cache-hit / cache-miss). Emptying the TRUE (cache-hit) part of the routine timed at 0.00 secs: the entire cache routine takes less than one hundredth of a second. I call that impressive! OK, on to the Cache-Lite class: |
||
The PEAR Cache_Lite() class: Overview: the idea is:
See above for an example.
|
||
Lite.php: Constructor: $cache = new Cache_Lite() // uses all defaults as below $cache = new Cache_Lite( $options ) $options array: $options = array(
'automaticSerialization' => FALSE, // (boolean) TRUE = can use with non-string data (slower)
'cacheDir' => '/tmp/',// (string) where to put files; must exist already;
// take care over access permissions; trailing slash required
'caching' => TRUE, // (boolean) TRUE / FALSE; enable / disable caching
'lifeTime' => 3600, // (int) cache lifetime in seconds
'fileLocking' => TRUE, // (boolean) enable / disable fileLocking
'fileNameProtection' => TRUE, // (boolean) TRUE = can use ANY cache id or group name
'memoryCaching' => FALSE, // (boolean) disable/enable in-memory caching (no lifetime)
'memoryCachingLimit' => 1000, // (int) max records to store in memory
'onlyMemoryCaching' => FALSE, // (boolean) disable / enable ONLY in-memory caching
'readControl' => TRUE, // (boolean) enable / disable read control
'readControlType' => 'crc32',// (string) 'md5', 'crc32', 'strlen' (slow->fast)
'writeControl' => TRUE, // (boolean) enable / disable write control
'pearErrorMode' => 1 // (int) (on raiseError call) 1 = CACHE_LITE_ERROR_RETURN
// (cf PEAR doc) 8 = CACHE_LITE_ERROR_DIE
);
Cache_Lite::Functions: $result = $cache->clean() // remove ALL files $result = $cache->clean( $group ) // TRUE = no problem $data = $cache->get($id, $group='default', $doNotTestCacheValidity=FALSE) // FALSE = no cache (NULL) = $cache->getMemoryCachingState($id, $group='default', $doNotTestCacheValidity=false) (NULL) = $cache->raiseError($msg, $code) // (int) $code $result = $cache->remove( $id, $group = 'default' ) // TRUE = no problem $result = $cache->lastModified() // Unix timestamp $result = $cache->save( $data, $id = NULL, $group = 'default' ) // TRUE = no problem (NULL) = $cache->saveMemoryCachingState( $id, $group = 'default' ) (NULL) = $cache->setLifeTime( $newLifeTime ) // in seconds (NULL) = $cache->setToDebug() // stop on error |
||