A little known feature of PHP’s static keyword is that it allows for memoization or function caching. This is a process whereby a functions heavy lifting can be cached so that subsequent calls are faster.
It is possible to store any value in a memoized way such as arrays or even objects. This is done without any external side effects - that is to say that the code calling the function will require no changes to support memoization.
This can be illustrated in the following example:
As you can each time the function is called it will return the same value, but just how does this work? Well let’s run down from the top.
First up a static variable is declared (
$rand) and this is the hidden secret that performs all the magic. It causes PHP to cache the value of the variable between calls to the function.
Next we set a value against the variable by calling
rand(). Note that this only occurs if the
$rand variable is null. Without this check the value would be changed on every call to
$rand is returned. It is clear from this example that you can implement this without changing the functions external API and in a way that subsequent calls reference cached information.
In contrast the same function without memoization would look something like this:
Here is another simple example that takes a slowish call to read a JSON encoded data set from a local file and parses it. The file does not change between function calls so it is an ideal candidate for memoization.
As you can see the subsequent calls to the
$json variable will use the pre-chewed data.
This effectively eliminates multiple calls to
json_decode(). Of course in the real production code you would include more checks before opening the file such as; does it exist? Is it actually JSON?
Through memoization you would remove the overhead of these checks during subsequent calls to
get_json_index() without the surrounding code needing to worry about the caching strategy used.
Whilst I have shown examples of functions this technique can also be used in exactly the same way on class methods not demonstrated here.
Although a simple technique it is very often overlooked or unknown. If you only need to cache a value in a function for the current execution cycle (on a web server this is one request) then there is no need to get complicated.
Caching mechanisms utilising NoSQL datastores such as memcached or redis or even the venerable APC can be overkill in many cases. The caveat to bear in mind however are that the variable is only accessible in and from the current execution cycle.
On the next cycle the value will be reset and other processes will have no access to it. So if you have many parallel workers operating on the same cache then this is not the method for you.
One final example I will include involves caching a function based on its parameters. A common place that this might be useful is when your caching database queries that vary dependent upon the functions parameters. In this case we might like to cache the blog posts by tag as they’re used in a listing and in a latest posts widget on the same page.
You can probably think of a number of other ways that this simple pattern can be used to speed up operations. Either way it is a handy technique both for functional and object oriented programmers.
It is also worth a quick note, even though it is obvious, that whilst this technique will give you a faster running site it will consume more memory so don’t go memoizing everything!
If you’re interested in more functional techniques like this then checkout my book; Functional Programming in PHP. A guide to advanced and powerful functional programming techniques in your favourite language.