Tuesday, August 5th, 2008...12:57 pm

Caching Part 2: Making It Easy

By: Robert Baskin (Online Director)

Jump to Comments

It’s time for the second post in my series about caching and how we use it here at the Yale Daily News. If you haven’t read the first part, you should: It introduces the series and some important concepts.

In the first post, I posted some sample code of something we do quite frequently: check for the existence of a cache object, if it’s set then get it, or if it’s not set, set it and then get it. We do this all the time, basically every single time we use our caching system. To avoid having to type out all of that code every single time, I wanted to create a function to wrap that logic.

I’m not very imaginative, so I called the function doCache. It takes three parameters: a name, an anonymous function, an object and an expiration time. The signature looks like this:

function doCache($name, $func, $object='', $cachetime)

Let’s go through each one of them. The name is simple: It’s just the name that you want to set for the cache object. It could be issue_index, article_1, author_1000, mostpopular, etc.

Now for $func and $object. At the time I was creating the caching system, I was also becoming more advanced with JavaScript (which is really a fantastic language that gets a bad rap because of the problems browsers have with the DOM, but that’s another discussion). In JavaScript, you can pass anonymous
functions as parameters into other functions and they can be used. I tried to adapt this for PHP.

Something I’ve wrestled with in writing this blog is defining a target audience. For now, I’ve decided to expect readers to have a fairly good technical background. While I will try and explain the concepts relevant to what I’m talking about as best as I can, I will sometimes link to explanations for those that are too broad to go into detail in a blog post. For example, I linked to an explanation of anonymous functions above. If you aren’t familiar with them, you should read the linked page then keep reading this post – it may make more sense.

The best PHP offers is create_function, which is a feeble stab at anonymous functions. The function takes two parameters: arguments and the code to execute inside the function. For example, let’s take the following code:

create_function('$model', 'return $model->getHomePage();')

That parameter is passed into doCache in the parameter $func. You also need an object to pass into the anonymous function so you can use it. That’s the third parameter of doCache. It’s frequently a model object – in this case, it’s the Issue Model, which retrieves the data for the home page. (I explain models a bit in the first caching post.)

So now inside doCache, if you call $func($object), $object is passed into that function as $model. The second parameter of create_function is the code you want to execute. So the getHomePage function of the $object, which as we said above is the Issue model, is called. So, if you had the code “$data = $func($object);”, $data would be set to the results of the getHomePage function.

There are two reasons why create_function is pretty bad. First, instead of just passing in a function, you need to pass in parameters to a helper function (the create_function function), which is unnecessary. That results in a second frustration point: If you have any quotes in your code, you have to escape them. Otherwise, they terminate the outer quotes of the second parameter, which are holding all of the code being passed into the second parameter of create_function. Very annoying.

The final parameter is $cacheTime, which is how long we want the cache object to live. My next post will discuss expiring caches, but basically, it indicates how long a $cacheHelper->get() should return the data before that object is considered invalid and must be generated again. In this example, it’s set to a default, but you could pass in a different value. I’ll get into it more next time.

So how does the final function look? Let’s check it out:

function doCache($name, $func, $object='', $cachetime=$default) {
    if ( $this->issetCache($name, $cachetime) ) {
        return $this->getCache($name);
    }
    else {
        $data = $func($object);
        return $this->setCache($name, $data, $cachetime);
    }
}

And a sample call:

$data = $this->Cache->doCache('issue_index', create_function('$model', 'return $model->getHomePage();'), $issueModel);

That one line of code makes our caching system work. All we had to do was go through our code, find all of the slow function calls (since we try and practice fat modeling, we often had just one function call to get all of the data) and wrap them in doCache. That helped ease the process of implementing the caching system across the site.

Up next: expiring caches, switching from file system to memory caching and view caching (the jackpot).

2 Comments

Leave a Reply

You must be logged in to post a comment.