Quick & basic Drupal caching

Published by Lennart Van Vaerenbergh on May 15, 2015

This post gives an overview of a couple of simple-to-implement caching principles in Drupal 7. When used correctly, it can really boost your Drupal performance.
 

Single page caching

When writing a function that does some heavy lifting, perhaps does a couple of database queries or other calculations, we can cache the result within the page request. This means that when the function gets called multiple times within that same page load, it doesn't have to do the heavy work time after time. Instead it does the calculations once and afterwards serves it from cache.

Example without parameters:
<?php
function my_module_function() {
  $result = &drupal_static(__FUNCTION__);

  if (!isset($result)) {
    // Do your expensive calculations here, and populate $result
    // with the correct stuff..
  }

  return $result;
}
?>
Explanation:
When calling this function, we first try to retrieve the result of an earlier call to this function (line 2). We check if there is a result (line 3). If not, let's do the calculations and return the result. Because $result was first set equal to drupal_static() by reference (using &), the static variable is automatically set and contains the result for a next call within the same page load. Drupal_static() requires at least one parameter, that's the name of the static variable. Usually __FUNCTION__ is used which is a PHP magic constant and simply returns the function name as a string. As Drupal 7 is mainly based on sequential programming, all function have to be unique, so can be used as a unique name for the static variable.

But what if the function has a parameter? We don't want a function that is called multiple times using a different parameter value returning the first result over and over.

Example with parameters:
<?php
function my_module_function($param) {
  $result = &drupal_static(__FUNCTION__);

  if (!isset($result[$param])) {
    // Do your expensive calculations here, and populate $result
    // with the correct stuff..
  }

  return $result[$param];
}
?>
Explanation:
To take into account the parameter in order to return the correct cached data, we use the parameter as an index in our cached result. The cached $result will be an array containing multiple results for each $param served to this function. When using more than one param, you could use a 2-dimensional array.

Many Drupal core functions such as the node_load() function use this principle. This means that when you do multiple calls to node_load() with the same node ID as parameter, there will be only one database call.
 

"Long term" caching

In order to cache results for a longer period than one page load, the Drupal cache functions can be used. The principle is the same as the example above, only will the cache stick for longer period of time.

Example
<?php
function my_module_function($param) {
  // Get single page cache.
  $result = &drupal_static(__FUNCTION__);

  if (!isset($result)) {
    // Get long term cache.
    if ($cache = cache_get('my_module::' . $param)) {
      $result = $cache->data;
    }
    else {
      // Do your expensive calculations here, and populate $result
      // with the correct stuff..
      cache_set('my_module::' . $param, $result, 'cache', REQUEST_TIME + (3 * 60 * 60));
    }
  }

  return $result;
}
?>
Explanation:
As from line 8, we are checking for cached data in the database using the function cache_get(). Data gets cached using cache_set() and is stored in a cache table, keyed by a unique key. In our case the key is "my_module:: + param value". Each of these database records will contain a blob holding the serialized data. If this function gets called multiple times over time with different param values (for example 333, 444, 555), we'll get something like this in the database:
  • Cache ID: {my_module::333} => Data blob: {result of the function}
  • Cache ID: {my_module::444} => Data blob: {result of the function}
  • Cache ID: {my_modyle::555} => Data blob: {result of the function}
On line 14, after doing the calculations, the result gets saved in the database ready to be served for a next call. How long the cache should be alive is up to you. You can give along a unix timestamp until when the cache should be valid. In our example the cache will be valid for 3 hours. When 3 hours have passed by, the cache will be rebuilt. Notice we use REQUEST_TIME to get (approximately) the current time and not the slower time() function. As this post is about performance, we better do it right :).
 

Cache render arrays

When building a custom page using render arrays, it can also be cached to a caching table. The mechanism is the exact same as the example above, only do we have to put the caching instructions in the render array while Drupal will handle the rest during the rendering.

Example:
<?php
$content['my_content'] = array(
  '#cache' => array(
    'cid' => 'my_module_data',
    'bin' => 'cache',
    'expire' => REQUEST_TIME + (5 * 60),
  ),
  // Other element properties go here...
);
?>
Explanation:
A render array exists out of multiple properties starting with a hash #. #cache is one of them. It tells Drupal to use the cache_get() and cache_set() function while rendering. Basically it's an array containing all 3 parameters of cache_set(). The rest is self-explanatory.
 

Clearing long term cache

There is a big chance that, at certain moments, you want to refresh the cache because important changes have emerged in your data. In this case you can implement the cache_clear_all() function.

Example:
<?php
cache_clear_all('my_module', 'cache', TRUE); 
?>
Explanation:
In this example, we are clearing all database records in the 'cache' table starting with 'my_module'. The third parameter is the wildcard, when set to TRUE, all database records starting with the string in parameter 1 will be deleted. Set to FALSE to delete the exact cache ID set in parameter 1.

Happy caching!


Sources: https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_static/7https://www.lullabot.com/blog/article/beginners-guide-caching-data-drupal-7
 

Add new comment

(If you're a human, don't change the following field)
Your first name.
(If you're a human, don't change the following field)
Your first name.
CAPTCHA
This challenge is for testing whether or not you are a human visitor and to prevent automated spam submissions.