Login

Implementing a Cache System in PHP

In this programming tutorial, you will learn how to create a simple caching system using a PHP segregated interface.

If you’re a PHP developer looking for a guide that teaches you the concepts behind implementing segregated interfaces and how to utilize them, then you have come to the right place. This series of articles will show you how to define fine-grained contracts for your classes, so that they can perform only the tasks they’re responsible for.

In the last installment of this series, I went through the development of a basic registry system, which was capable of using different registry classes to store, retrieve and even dump data. The most engaging aspect of this sample system was that the swappable registry classes implemented a couple of segregated interfaces in order to execute the aforementioned operations.

As with other elements of object-oriented programming, it’s possible to use segregated interfaces in a great variety of scenarios and conditions and, therefore, enjoy the benefits that they provide right out of the box.

If you missed the first two parts in this series, or need a quick refresher, you can find them at:

As I stated in the introduction, my goal in this article is to create an extendable caching system based on the contract defined by a segregated interface. To achieve this, the first step we need to take is to create the interface in question.

The following code creates an interface we will call “CacheableInterface”, which sets a contract that outlines the behavior of an abstract cache back-end. Check it out:

(CacheableInterface.php)

<?php

interface CacheableInterface { public function set($key, $data);

public function get($key);

public function delete($key);

public function exists($key); }

As shown above, the “CacheableInterface” interface declares a set of methods that permit you to create several different cache back-ends with minor effort. You should pay particular attention to the contract established by the pertinent methods: effectively, any further implementer will have only the functionality required for setting, fetching, checking and even removing elements from the underlying cache mechanism.

This example clearly shows how the use of a segregated interface may help in the creation of classes that have a well-defined range of responsibilities.

Now that our granular contract exists, the next step is to create a couple of them, which will allow you to cache data using both the APC PHP extension and the file system as well.

{mospagebreak title=Building Multiple Cache Back-ends in PHP}

Building a couple of implementers of the previous “CacheableInterface” interface is a pretty straightforward process. As I expressed before, the first cache back-end that I want to show you is a simple wrapper for the APC PHP extension, and its source code is as follows:

In the above code snippet, the “ApcCache” class acts like a proxy for the most relevant methods included in the APC extension, which allows you to store, fetch and delete data from shared memory. The class is pretty similar to the one that I developed in this previous article (http://www.devshed.com/c/a/PHP/Swapping-Cache-BackEnd-at-Runtime-in-PHP/), so if you had the chance to read the tutorial, understanding how this cache back-end works should be a breeze for you.

Now, take a look at the following class, which also implements the “CacheableInterface” interface, only this one caches data using the file system:

This file-based back-end caches data in a specified file, located under the default “cache” directory (although this option can be easily changed). In addition, the class is capable of retrieving and deleting cache files as well, in accordance to the contract set by the “CacheableInterface” interface.

At this point, you saw how easy is to spawn a couple of cache back-ends based on the mentioned interface. Given that, the last thing that needs to be done to get this sample cache system up and running is create an adapter capable of consuming the previous cache classes via dependency injection.

So far, so good. Having built a basic adapter that uses the “Plug-in” pattern to work with the previous cache back-ends (or eventually any other, as long as it implements the “CacheableInterface” interface), the last step that must be taken is set up an example that shows how to utilize this cache system.

{mospagebreak title=Cache Data in RAM with PHP}

Putting all of the pieces together: seeing the previous cache classes in action

If you’re anything like me and want to see how to put the earlier caching system to work, below I created a couple of scripts that will hopefully be of help in this case. Here’s the first one, which uses the “ApcCache” backend to cache in RAM some information about a fictional user:

Mission accomplished. Even when this couple of examples are somewhat basic, they come in handy for demonstrating how the usage of a single segregated interface may be an invaluable resource in the development of an extendable caching system.

And speaking of extending things, there’s plenty of room to enhance the functionality of this sample system. So, if you have some time off and want to do something productive with it, go ahead and add to the system a whole new cache backend. All that you’ll have to do is create an implementer of the “CacheableInterface” interface. It’s that simple, indeed.

Final thoughts

Over this third episode of the series, I recreated yet another scenario where the use of segregated interfaces can be of great help in the development of truly “pluggable” systems. In this particular case, I appealed to a single interface to create from scratch a simple caching library, but logically it’s feasible to extend this concept to others fields with the same ease.

Considering that I have already at disposal two cache back-ends ready to be put in action, it’d be really a shame not to reuse them. To prevent this from happening, in the coming tutorial I’m going to develop a customizable user model, which not only will make use of the pertinent back-ends, but it’ll utilize a MySQL abstraction class to access the underlying storage mechanism.