Alternative PHP Cache

APC has been around for quite a while. Mostly known as an opcode cache for PHP, it can do quite a few other things. Of course, this requires a certain level of control on the web server’s configuration. The extension allows to easily store and retrieve values from shared memory. A simple call to apc_store() and the value is ready to be read by an other request. Even storing the results in a file is more complex than using the APC extension.

if( !$result = apc_fetch( 'my_result' ) )
    $result = $dbh->query( "SELECT ..." )
        ->fetchAll( PDO::FETCH_ASSOC );

    apc_store( 'my_result', $result, 3600 );

The piece of code above transparently fetches the result from the cache or generate it if required, then store it for an hour. Sure, it takes a few more lines than a simple query, but it’s not that complicated. The results are terrific. I used it on a query that takes one or two seconds to execute, which is not that long, but the delay is just enough to be annoying on an intranet where users expect the page loads to be instant. With the cache, the page load time goes back to the instant level, except the first time the query is executed.

It can just as easily be used to cache queries with a parameter.

$key = "my_result_$id";
if( !$result = apc_fetch( $key ) )
    $result = $dbh->query( "SELECT ... $id ..." )
        ->fetchAll( PDO::FETCH_ASSOC );

    apc_store( $key, $result, 3600 );

I use 0 as my cache duration, which means it’s destroyed only when the web server is restarted (never, right?). Some of these results rarely change. Using a 5 minutes cache would allow to keep the data up to date when it changes, but it removes the whole advantage on an application that receives a few actions per minute only. Using a larger value, such as 1 hour does not make sense because the changes would not appear fast enough, so I decided to use infinite cache and clear it manually when needed.

The cache can be cleared manually using apc_clear_cache(), but I don’t really like removing all values at once. If I perform an operation that requires the cache to be cleared for a given set of results, I don’t want the entire cache of the application to be destroyed. I use a function that looks like this one:

function clear_cache( $prefix )
    $list = apc_cache_info( 'user' );
    foreach( $list['cache_list'] as $row )
        if( strpos( $row['info'], $prefix ) === 0 )
            apc_delete( $row['info'] );

clear_cache( 'my_result' );

Even if you don’t need opcode cache, it’s worth taking a look at APC.

Leave a Reply

Your email address will not be published. Required fields are marked *