Static variables and Drupal install profiles


I believe that this is not an issue with Drupal 7 as it handles variables differently than D5/D6. However, if you want to make an install profiles for anything earlier than D7 static variables can pose a huge problem. Static varibles are used for caching within a function in PHP. Generally the first time the function is called during a page load the static will be set. The second time it's called there's no need to execute most of the code and the value stored in the static will be returned.

While statics can be convenient and help improve performance, they become a huge problem when the relevant data has been altered partway through a page load and you need to reset the cache. Since the install profile is executed in what's effectively a single page load, static variables become problematic.

An example Drupal API call that uses static variable caching is the filter_formats function.

In our wedful install profile we have a function that creates and configures my input filters. Some modules create their own input formats and we want to handle these in a generic way. Using filter_formats() we can get a list of all formats, and then apply specific permissions and configuration options to those.

  $formats = array();
  foreach (filter_formats() as $id => $format) {
    $formats[$format->name] = $id;
  $filtered = $formats['Filtered HTML'];
  $full = $formats['Full HTML'];
  $php = $formats['PHP code'];

You can reference any of the input formats by name this way, since the ID might not be guaranteed to be the same every time your install profile runs. From here you can assign permissions and adjust the specific input filter settings. (I recommend using the install_profile_api module to help with any of these things).

The only catch is that this doesn't work. filter_formats() uses static caching with no way to reset that cache. And unfortunately there's no clean workaround for it. Of course you can simply run SELECT * FROM filter_formats but this is hardly desirable. And in some cases the function is a lot more complex.

I lost many hours to problems relating to static variables. So if you're implementing an install profile and having a bizarre problem with any Drupal API calls it's quite likely it's due to static caching and you may need to just make your own local version of the function that works.

Peanut Gallery

That's almost an official drupal design pattern

Or should that be an anti-pattern.

Copying a function and then undoing the parts that are going to fuck you is nearly the only way to accomplish some things.

It can sometimes get out of hand though, if one of the functions you need to call makes use of this function waaaay down the tree, and you end up having to micro-fork all the functions down. (see anything relating to themes).

Update too

hook_update suffers a similar issue but in two ways.

Update is run in a batch (as I though install was) and if you statically cache something and the batch iterates on (eg it took a long time and had to "tick" to update the screen) then it's essentially a new request and I had a LOT of trouble with static variables getting reset when I didn't expect them to.

The other issue I had was basically the same as above - a function which statically cached with no way of overriding. My solution (during update) was to test if that function returned an expected value, if not, variable_set a semaphore and fail that update. This would cause me to have to run update.php twice, but the second time the function's static cache would be cleared and would return the expected results (and thus the sempahore could be reset).