5

Imagine I have a hard-to-compute value.

$my_heavy_value = compute_heavy_value();

What's the difference, at performance level, between storing the computed value using drupal_static() and using \Drupal::state()?

Which one is stored in the database? Is there one that is stored in memory?

3 Answers 3

13

They perform different tasks.

drupal_static() only stores data for the current page load (or ajax load). For example, if you are loading something from a database table multiple times on a single page load (ie - a user account), the first time it is loaded it is saved to memory, and the next time it is needed, it is pulled from memory, rather than reloading it from the database, saving that second database query.

Drupal::state() saves data to the database, where it can be recovered in future requests. It's a cache of sorts.

You can actually use them in conjunction with each other as follows:

function get_some_value() {
  // Instatiate the static
  $value = &drupal_static(__FUNCTION__);
  // Check if the value has already been set in this page load
  if(is_null($value)) {
    // The value has not yet been set for this page load,
    // so retrieve it from the state if it exists, and if it
    // does, then save that to the static
    $value = \Drupal::state()->get('my_value');
    // Check if the value was retrieved from the state
    if(!$value) {
      // The value was not retrieved from the state, so
      // it needs to be generated. Below is an example
      // fetching it from the database
      $value = db_query('SELECT some_value FROM {some_table} WHERE some_column = :some_value', [':some_value' => 'some value'])->fetchField();

      // Save it to the state for future page loads
      \Drupal::state->set('my_value', $value);
    }
  }

  // Return the value
  return $value;
}

With the above code, the first time this function is hit, it will first check if the value exists in the static cache (this page load), and when it doesn't, it attempts to retrieve it from the state cache, and when it doesn't it finally generates it with a database query, saving it both to the static cache, as well as the state.

If it hits this function again on the same page load, the value will be in the static cache, so none of the internal code is needed, and the value is returned from the static cache.

On a future page load, the first time this function is hit, nothing is retrieved from the static cache, so it will pull it from the state cache. If the function is hit again on that page load, the value will be in the static cache and returned from that.

-- Edit from comments --

Note that if you use Drupal::state as cache, you will then need to manage expiration on your own. If you nee in-memory caching, use the drupal_static cache. If you need a persistent cache, it is likely better to use \Drupal::cache than to use Drupal::state.

2
  • It might be worthwhile to add that it is better to not use Drupal::state as cache, since you will then need to manage expiration on your own. If you need both in-memory caching (static cache) and a more persistent cache for the value of your expensive operation, I would recommend using \Drupal::cache()->set() and \Drupal::cache()->get(). This API is purpose-built for your use case. Avoid \Drupal::state() as a cache.
    – apotek
    Commented Jul 27, 2023 at 16:35
  • I updated the post with your info.
    – Jaypan
    Commented Jul 27, 2023 at 17:16
8

drupal_static() is used to cache data within a single page request. it stores the data in a static variable.
The class returned by \Drupal::state() handles values that need to be preserved between requests. As such, it is probable it stores its values in a database table. (It depends from the exact implementation done from that class.)

drupal_static() is faster since it saves its values in the memory, but using states doesn't make a lot of difference.

As for recommending one, both are recommended. It's up to you using the one that suits your needs. Do you need a cross-request value, or a value you use only in one request?

If you are looking to replace drupal_static() with OOP code, Drupal 8.6 introduced the MemoryCache class, that stores cache items in memory using a PHP array. It has been added to allow classes that would previously maintain state on a protected property (as a static cache to avoid persistent cache or database lookups) to inject a service to hold that state instead. (See Added memory cache.)
Notice that the class isn't used directly. The module needing it should define a new service, similarly to what Drupal core does with the entity.memory_cache service.

entity.memory_cache:
  class: Drupal\Core\Cache\MemoryCache\MemoryCache
6

When you want to store hard to compute data in memory you use a static variable. But to store this data in the database the State API is not the right place, despite the similar name:

The State API provides a place for developers to store information about the system's state.

A system state is for example the last time cron has run. So the State API \Drupal::state has nothing to do with caching at all.

Use the Cache API Drupal::cache() instead.

Example how to store data in cache:

\Drupal::cache('data')->set($cid, $data, Cache::PERMANENT, ['heavy:' . $heavy_id]);

$cid is a unique cache key, which is used to retrieve the data from cache:

$data = \Drupal::cache('data')->get($cid);

You can use the cache tag you've set above as fourth parameter to invalidate the cache entry if it becomes outdated:

\Drupal\Core\Cache\Cache::invalidateTags(['heavy:1']);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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