Quick PHP caching

I received a question today:

I have some quick caching questions. What is the quickest way to get data into a PHP script? I have some data, I could store it in a database, but I want to avoid that dependency and slow down. I want PHP to compile the file into some data that it can access easily in the script’s name space. Periodically (every 1-2 mins) the system will check the modified time on the file, if it is different, it will reload the data.

The data is not large.

Speaking of caching, what is the best script system for caching these days APC?

Quick and dirty variable caching

Well, if you don’t want to code at all there is PEAR::Cache_Lite.

The basic approach I use is to serialize() the stuff into an object or array hash and then save it to the file. To get the data, I do an file_get_contents() and unserialize() on the file.

To deal with the stale cache issues, you simply take advantage of the file system checks as he mentioned using filemtime(). A Linux system is pretty good at managing disk caching issues on constant fstat checks, so you usually don’t have to worry about the hit.

The problem with a file-based cache is a race issue between two PHP processes that occurs during writes and writes and reads. The standard way of dealing this in PHP is with portable locks, but I much prefer George’s link trick. The idea here is that a link occurs instantaneously so during write you compose the thing and then transfer it over.

Here is the code:

$max_stale_time = 60 * 3; //3 minutes to stale
$cache_filename = 'filename.ser.php';

if (file_exists($cache_filename) && filemtime($cache_filename) + $max_stale_time > time()) { //not stale
    $data = unserialize(file_get_contents($cache_filename));
} else { //stale
    // generate variables here, assume that they are in $data

    $tmp_file = tempnam(sys_get_temp_dir(), ''); //or ini_get(...)
    file_put_contents($tmp_file, serialize($data));
    @unlink($cache_filename); //the @ is for a race on these two steps
    @link($tmp_file,$cache_filename);
    unlink($cache_filename);
}

About APC

There are a lot of arguments about what the best PHP code caching system is. You can choose between Zend Cache, APC, Turck MMCache, afterburner*CACHE, and ionCube PHP accelerator. Personally, I recommend APC only because it will be built-into PHP6.

The thing is you probably want to mix these two solutions. By this I mean APC has its own shared memory system for storing any data using apc_store() and apc_fetch(). You should probably save whatever you want to cache into APC’s shared memory cache instead of the file system.

$max_stale_time = 60 * 3; //3 minutes to stale
$cache_filekey = 'cache';

list($time,$data) = apc_fetch($cache_filekey);
//you might run into issues here on the first cache store because apc_fetch returns false
if ($time + $max_stale_time < time()) { //stale
    //generate variables here, assume that they are in $data

    apc_store($cache_filekey,array(time(),$data));
}

Does anyone have any better advice? I haven’t worked on massively scaled PHP installations so my answer is probably wrong.

4 thoughts on “Quick PHP caching

  1. @Ben: Good point. I didn’t think to mention things like the memcached extension because that sort of scaling isn’t needed until your app gets very, very big.

    In that it’s probably a good idea to abstract your caching code so that you can put a factory in front of it (later) and seamlessly switch to memcached.

  2. I noticed you have “unlink($cache_filename);” on line 13 of your first example code. That will delete the data you have just cached, I think you meant to put “unlink($tmp_file);” ins tead.

Leave a Reply to Tom Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.