2

I understand Drupal static cache is used to store static values in the memory for the length of the request to faster access them. However throughout Drupal and contributed modules I tend to see two different versions:

Example from drupal_is_front_page:

function drupal_is_front_page() {
  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['is_front_page'] = &drupal_static(__FUNCTION__);
  }
  $is_front_page = &$drupal_static_fast['is_front_page'];

  if (!isset($is_front_page)) {
    // As drupal_path_initialize updates $_GET['q'] with the 'site_frontpage' path,
    // we can check it against the 'site_frontpage' variable.
    $is_front_page = ($_GET['q'] == variable_get('site_frontpage', 'node'));
  }

  return $is_front_page;
}

They way I read (and used) it from some tutorial I once found:

$static_cache = &drupal_static(__FUNCTION__);
if (!isset($static_cache[$key])) {
  // Obtain value
  $static_cache[$key] = $obtained_value;
}

return $static_cache[$key];

So I skipped the static declaration of the local variable, and to be honest I don't see why I should be adding it, it is in the first line of drupal_static:

function &drupal_static($name, $default_value = NULL, $reset = FALSE) {
  static $data = array(), $default = array();
  // First check if dealing with a previously defined static variable.
  if (isset($data[$name]) || array_key_exists($name, $data)) {
    // Non-NULL $name and both $data[$name] and $default[$name] statics exist.
    if ($reset) {
      // Reset pre-existing static variable to its default value.
      $data[$name] = $default[$name];
    }
    return $data[$name];
  }
  ...
}

Is is even faster if I declare another static variable in my module to hold a function that manages a static variable? (The name drupal_static_fast implies this.) Is this some old Drupal 6 convention where there was no drupal_static and it had to be declared locally? Or am I missing something else?

  • 2
    There are two static cache patterns - normal, and fast. Normal is used for, well, normal cases ;) Fast is used in functions that are called very often in a single page request. It will always be marginally faster if you don't use Drupal's static cache methods at all in your own code. But then you can't clear those static caches from another function, which is kinda the whole reason Drupal has this feature in the first place. I rarely use it for project-specific modules, unless another module in the same project would need to clear the particular function's cache – Clive May 4 '16 at 16:02
  • @Clive is right, it is often unnecessary in project-specific code, I see colleagues insist on it just for the sake of it. And even if you do want to be able to reset from outside, there are faster ways than $drupal_static_fast, see 3v4l.org/ZqHdj – donquixote Mar 14 at 23:51
4

The code in drupal_is_front_page() makes the page rendering faster because it calls drupal_static() once for all the page request; how much faster depends from how many times drupal_is_front_page() is called. The fact it is using that code means the core maintainers know the function is called many times, enough to need that code.
The drupal_static() documentation explains this with the following paragraph:

In a few cases, a function needs a resettable static variable, but the function is called many times (100+) during a single page request, so every microsecond of execution time that can be removed from the function counts. These functions can use a more cumbersome, but faster variant of calling drupal_static(). It works by storing the reference returned by drupal_static() in the calling function's own static variable, thereby removing the need to call drupal_static() for each iteration of the function. Conceptually, it replaces:

$foo = &drupal_static(__FUNCTION__);

with:

// Unfortunately, this does not work.
static $foo = &drupal_static(__FUNCTION__);

However, the above line of code does not work, because PHP only allows static variables to be initialized by literal values, and does not allow static variables to be assigned to references.

The example below shows the syntax needed to work around both limitations. For benchmarks and more information, see http://drupal.org/node/619666.

function user_access($string, $account = NULL) {
  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
  }
  $perm = &$drupal_static_fast['perm'];
  // ...
}

Your code calls drupal_static() every time, and essentially is the same code as the following one, which in Drupal documentation is not considered the fast version.

  $added = &drupal_static(__FUNCTION__);

  // User-uploaded files cannot set any response headers, so a custom header is
  // used to indicate to ajax.js that this response is safe. Note that most
  // Ajax requests bound using the Form API will be protected by having the URL
  // flagged as trusted in Drupal.settings, so this header is used only for
  // things like custom markup that gets Ajax behaviors attached.
  if (empty($added)) {
    drupal_add_http_header('X-Drupal-Ajax-Token', '1');
    // Avoid sending the header twice.
    $added = TRUE;
  }

@Clive explained the reason drupal_static() was added to Drupal: The idea behind its implementation was to use a static variable that at the same time could be reset (or changed) from other functions as well. In fact, the drupal_static() documentation says:

All functions requiring a static variable to persist or cache data within a single page request are encouraged to use this function unless it is absolutely certain that the static variable will not need to be reset during the page request. By centralizing static variable storage through this function, other functions can rely on a consistent API for resetting any other function's static variables.

  • 1
    Apparently I did miss something, I didn't understood this the first time I read the documentation (in fact I did not even notice the drupal_static_fast version). But summarizing; the way I implemented it is perfectly valid and is the general way of using this function. However for often called requests it can be enhanced a bit more by defining a local static variable as well? – Neograph734 May 4 '16 at 17:22
  • 1
    Exactly. Since they benchmarked the code, I guess they found the fast version makes quite a difference. – kiamlaluno May 4 '16 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.