Many functions (and methods) in a project will often provide the same return value for the same arguments, like:
- mathematical functions:
function SomeMaths($x)
{
return $x + pow($x, 3.2) - cos($x);
}
- functions which retrieve content from a file:
function GetConfiguration()
{
return parse_ini_file('configuration.ini');
}
- functions which retrieve content from a database:
function GetArticleById($id)
{
$sqlId = mysql_real_escape_string($id);
$result = mysql_query("SELECT `id`, `title`, `content` FROM `article` WHERE `id` = '$sqlId' LIMIT 1");
if (FALSE === $result)
{
throw new Exception('Query failed.');
}
return mysql_fetch_assoc($result);
}
If your project holds a function like one of these, and:
- your prefered profiling tool reveals that a lot of the execution time is spent in this function
- its returned value is always the same during a single run (script execution), when providing the same arguments
- this function is called more than once per run
Then consider caching (saving) its return values.
Here is how it can be achieved: just add a static variable in the body of the function, which will hold an associative array, mapping every parameter combination with a return value:
function GetArticleById($id)
{
static $cache = array();
// Return value is not in cache yet?
if (!isset($cache[$id]))
{
$sqlId = mysql_real_escape_string($id);
$result = mysql_query("SELECT `id`, `title`, `content` FROM `article` WHERE `id` = '$sqlId' LIMIT 1");
if (FALSE === $result)
{
throw new Exception('Query failed.');
}
// Add return value to cache
$cache[$id] = mysql_fetch_assoc($result);
}
// Return cache content
return $cache[$id];
}
Here it is, the (possibly heavy) process of querying the database will only be executed once at the first function call. Every other function call with the same argument will use the cached return value.
Keep in mind that the amount of cached return values must be reasonable (available memory is limited). If there are millions of possible arguments combinations for a function in a single run, you’ll have to consider a more elaborate way of optimizing it (this could be the subject of a future post).
Also, always, always, ALWAYS profile your code BEFORE you decide to apply an optimization like this one (and wait for your project to be nearly completed before profiling).