You might think "Memoization" is a typo, but it's not. Memoization is a simple technique to improve software performance. Unfortunately, the technique relies upon repetitive boilerplate. In this article, I show you how to use memoization without any boilerplate code.
In computing, memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.
In PHP, memoization looks like this:
function getResult() { static $result = null; if (null === $result) { $result = /* some expensive calculation */ } return $result; }
The logic is easy to follow: if I haven't calculated
$result
already, do so. Every other time I'm asked for $result
return what I previously calculated.You might see this in other variations, where the
if
works with an empty()
or a ! isset()
check. The point is, though, there is a pattern. The only part that changes is the expensive calculation part.Is it possible to abstract this operation into a function, so that we don't have to write the same boilerplate over and over? Why yes, friends, there is!
Do not repeat yourself
A simple function abstracts this boilerplate into a tight package:function memoize($initializer, $key) { static $data = []; if (! array_key_exists($key, $data)) { $data[$key] = call_user_func($initializer); } return $data[$key]; }The first formal parameter
$initializer
is any callable. The second, $key
, is what you would like to uniquely name this calculation. The first call to memoize
with that key will memoize the result of the initializer callable. Subsequent calls will return the memoized value.
Usage and test cases
By way of demonstration, here is the PHPUnit test case.class MemoizeTest extends \PHPUnit_Framework_TestCase { public function test_initializes_and_returns_value() { $expect = rand(); $actual = memoize( function () use ($expect) { return $expect; }, __FUNCTION__ ); $this->assertEquals($expect, $actual); } public function test_initializes_same_key_only_once() { $count = 0; memoize( function () use (&$count) { $count++; }, __FUNCTION__ ); $this->assertEquals(1, $count); memoize( function () use (&$count) { $count++; }, __FUNCTION__ ); $this->assertEquals(1, $count); } }
The future
Memoization is seen everywhere in PHP. Frameworks, especially, use the technique. Framework maintainers might consider includingmemoize
in their code base to reduce the repetitive code. It may even be pragmatic to push a function like this into the language itself, to gain a further (but admittedly small) advantage.
0 comments:
Post a Comment
Share your thoughts!