Registry Design Pattern with Lazy Load
The registry design pattern is a great way to store info throughout your application. But certain information isn't necessary on each request - and you don't always know when you will need it. We've taken the basic registry design pattern and added lazy load capabilities to give you optimum performance and save resources.
Example
Let's say you are storing application info in your registry. This info is needed often, and is populated with a database call. But there are many requests where this information is not needed. The solution is to lazy-load the info into your registry so it is always available when you need it, but never using resources when you don't.
Before:
<?php
$q = Your_Registry::get('dbh')->query('select * from infoTable');
$info = new stdClass;
while ($r = $q->fetch()) {
$info->name = $r['name'];
$info->foo = $r['foo'];
}
Your_Registry::set('info', $info);
echo Your_Registry::get('info')->name;
?>
Although this wasn't a complex query, it will hit your database server unnecessarily on requests where you don't need access to this info. Using our modified registry pattern with lazy load and closures (anonymous functions), we can improve performance.
After:
Let's store this process inside of a closure, and pass it as an argument to our lazyLoad() method along with the registry key we want to associate it with - in this case, info.
<?php
Your_Registry::lazyLoad('info',
function() {
$q = Your_Registry::get('dbh')->query('select * from infoTable');
$info = new stdClass;
while ($r = $q->fetch()) {
$info->name = $r['name'];
$info->foo = $r['foo'];
}
Your_Registry::set('info', $info);
}
);
?>
Now when get('info') is called, if that key does not exist in our registry store, the class will check to see if we have associated a lazy load function with that key. If so, it will execute the function (which saves to the registry), then give us the information. It will also erase the lazy load after executing, and future requests for this data within the same script execution will be pulled directly out of the registry store.
Note: If you aren't running PHP >= 5.3, you will not be able to use closures and will instead need to use create_function(). You can also create a regular function, and pass in the function name as a string, then use call_user_func() within the get() method to execute the function.
Download
Here is the modified registry pattern with lazy loading added.
<?php
class Your_Registry
{
protected static $_instance = null;
protected $_store = array();
protected $_lazyLoad = array();
private function __construct() {}
public static function getInstance()
{
if (is_null(self::$_instance)) {
self::$_instance = new self;
}
return self::$_instance;
}
public static function lazyLoad($key, $func)
{
self::getInstance()->_lazyLoad[$key] = $func;
}
public static function remove($key)
{
$instance = self::getInstance();
if (self::isRegistered($key)) {
unset($instance->_store[$key]);
}
}
public static function get($key)
{
$instance = self::getInstance();
if (isset($instance->_store[$key])) {
return $instance->_store[$key];
}
if (isset($instance->_lazyLoad[$key])) {
$instance->_lazyLoad[$key]();
unset($instance->_lazyLoad[$key]);
return $instance->_store[$key];
}
return false;
}
public static function set($key, $value)
{
self::getInstance()->_store[$key] = $value;
}
public static function isRegistered($key)
{
return isset(self::getInstance()->_store[$key]);
}
public function __clone()
{
throw new Exception('Cannot clone ' . __CLASS__ . ' class');
}
}
?>
Comments
Let us know what you think!