Zend Framework Hidden Gems: Zend_Cache

      6 Comments on Zend Framework Hidden Gems: Zend_Cache

Caching isn’t one of those things that many people think of when designing their first applications. However once they launch their new AJAX enabled web2.0 application, they might start wondering what they can do to get this beast to move faster. The answer is caching.

The first step people take is to enable a front end cache, this might be a hardware solution or a software caching proxy such as squid. But for that web2.0 app which requires extremely dynamic content, you will find that traditional caching solutions won’t work. You will soon find that caching needs to be designed into your application and work on several different layers.

In my “Advanced PHP Tools” tutorial at the International PHP Conference in Frankfurt I had my attendees do a show of hands for what types of caching solutions were used. Out of the 40+ attendees, about half had implemented their own cache layers and while it’s not difficult to create a caching mechanism, by definition caches need to be fast and speed is something that is difficult doing on your own. There are several good PHP caching solutions however, since this series is about Zend Framework, we will examine Zend_Cache which is a good solution and offers some innovations in how caches are handled.

Getting started

As with all Zend Framework packages, to get started simply include the package which you need. In this case it’s Zend/Cache.php, I have the Zend Framework in my PEAR install path, so I don’t need to fiddle with my install path. Instead of requiring the actual class file, you can require the top-level Zend.php and then use the loadClass method, but for such a simple example that is unneeded overhead.

Let’s jump into some example code:

In the first 3 lines of this example we create our instance of the Zend_Cache class. Zend_Cache uses a modular approach to specify the frontend and backend drivers. The frontend drivers determine what data is gathered and from your PHP script. The backend driver determines how the data is stored. In this example we are using the “Core” frontend driver, which is the top-level frontend driver which provides functionality that all other frontend drivers inherit. The “File” backend driver provides file-based storage for your cached data.

Each of the drivers accepts multiple parameters, for the sake of simplicity in this example, I am only specifying that the “lifetime” of the cache be 10 seconds, and the cache data should be stored within the ‘./tmp’ folder. Ensure that this folder is created before you test the above example. As of version .02 of the Zend Framework, Zend_Cache will fail silently if the folder does not exist.

Once we have our object, we will use the get() method to check if an entry with the id of ‘time’ exists in the cache. The $result returned from get() will either contain the cached string, or false if the string is not cached. If the string was not cached we generate a new string and save it. If the string is cached then we simply echo the string to the browser.

And that’s all there is to it.

Well, actually there is a lot more to it, we’ll cover some of it here.

Tags

In our simplistic example we have one string that we are caching. In a real-world application you are likely to have several pieces of information which are cached for every operation. You will want to be able to manage these pieces of cached data as a group and not have to worry about remembering all the ids of your saved data.

To handle this, Zend_Cache has implemented a tagging system. In Zend’s tagging system you can tag each cache entry with multiple tags, and unlike the IDs, tags do not have to be unique. This means that you will have multiple cache entries using the same tag, and are able to manage these as a group. The tags are specified as an optional parameter to the save() method.

As an example:

Here we are creating several entries into our cache system, but are using tags to separate them into logical groups. We have a group for our date/time information, and then a group that stores the specific user information. We are going to use the clean() method to force the removal of the instance data, but will retain the userdata for future use.

You will notice the use of a class constant in the above example. Zend Framework has set a standard of using class constants (using the ‘const’ construct) instead of global constants (using define()) whenever possible, this keeps the global constant space clean.

Tags are only available in the file-based backend drivers.

Frontend Drivers

If you tried to create an example using the above code, you probably found that Zend_Cache threw an exception. The reason for this has to do with the way the data is stored in the cache. Since we specified that the information will be stored in the “./tmp” folder..

In the file storage driver, you’ll find each ID is stored in it’s own file which is named using the unique id prefixed with “cache_”. Inside this file you will find a timestamp and then the data string. Because we have only been storing strings, things have been simple for the backend driver, but when we wanted to store an array which we will later want to fetch as an array, the default string storage doesn’t work. Zend_Cache handles storing various datatypes using PHP’s handy serialization method. We can specify this when setting the frontend driver options.

There are several existing frontend drivers available, all of which have their place as caching solutions for various scenarios. The next example we will look at is the function call cache.

The function cache is useful when you have very expensive functions and you don’t need to call the function on every request. In the following example I have created a function which waits for 20 seconds before returning the date.

Through configuration options you can indicate what functions you want cached and which you want never to cache. This way you can pass all your function calls through the cache and then tweak which functions you need cached directly from the configuration options.

There are a lot more interesting frontend drivers, but I hope these examples whet your appetite and show what is possible through this package.

Backend Drivers

So far in this short tutorial, we have only played with the File backend driver. The File backend is useful because it is easy to set up, however in a scenario where you need extremely fast caching, you will probably not want to slow yourself down with multiple filesystem hits.

To address this issue Zend_Cache has supplied drivers which allow you to store your cache in memory using either the memcache or APC extensions available from pecl. Using a memory based backend driver will speed up your code cache execution since the filesystem will not need to be touched during the execution of your scripts. Using memcache you will also be able to share your memory between machines enabling a cluster of machines to share the same cache. The downside of memory based caches, is that as of Zend_Framework .02 they do not support tags.

The final driver available is the SQLite backend driver which stores the cache results in an SQLite database (surprise!).

Choosing the backend driver is really a personal decision, there are benefits to each option and usually only good benchmarks will let you know which backend driver is appropriate in your situation. In most cases the filesystem cache will be sufficient. In many cases the OS will be clever enough to use the filesystem cache and serve out data quickly when you are making a lot of filesystem requests.

In Conclusion

Zend_Cache is still fairly young, and has quite a bit of growing to do. However, it is a promising solution and can be used either as a standalone package, or as part of the Zend Framework. The drivers are still very young, and as seen with the lack of tagging functionality in non-filesystem based drivers, still need some work. There is also no support for SHM or database backends, and the frontend drivers available are not as numerous or mature as other Cache systems (such as PEAR::Cache).

However the ease-of-use make this package lots of fun to work with and I’m looking forward to seeing it grow in to a full featured caching package.

Click Here to vote for this article on dzone.com.

The Zend Framework is a community based project. If you are interested in learning more or contributing to it, visit this page.