Drupal - Difference between drupal_static and \Drupal::state?

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.


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

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']);

Tags:

Performance

8