DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Lazy Registry Class

03.30.2010
| 2704 views |
  • submit to reddit
        Managing globals with the registry pattern. This class provides lazy loading functionallity. This means it is possible to add a callback or class (with arguments) which will be called or instanciated when it is being used for the first time.

<?php
/**
 * LRegistry Class
 *
 * Managing globals with the registry pattern.
 * This class provides lazy loading functionallity. This means it is possible to
 * add a callback or class (with arguments) which will be called or instanciated
 * when it is being used for the first time.
 *
 * @version  1.0
 * @author   Victor Villaverde Laan
 * @link     http://www.freelancephp.net/php-lazy-registry-class/
 * @license  MIT license
 */
class LRegistry {

	/**
	 * Singleton pattern
	 * @var Registry object
	 */
	private static $_instance = NULL;

	/**
	 * Containing all entries
	 * @var array
	 */
	private $_entries = array();

	/**
	 * Default overwrite entries when being set more than once
	 * @var boolean
	 */
	private $_default_overwrite = TRUE;

	/**
	 * Private contructer for singleton protection
	 */
	private final function __construct() {
	}

	/**
	 * Private clone method for singleton protection
	 */
	private final function __clone() {
	}

	/**
	 * Get instance of this class
	 * @return Registry object
	 */
	public static function get_instance() {
		if ( self::$_instance === NULL )
			self::$_instance = new LRegistry;

		return self::$_instance;
	}

	/**
	 * Get value of given key
	 * @param string  $key
	 * @param boolean $reload  reload if class or callback was already loaded
	 * @return mixed
	 */
	public static function get( $key, $reload = FALSE ) {
		$instance = self::get_instance();

		// check if entry exists
		if ( ! key_exists( $key, $instance->_entries ) )
			$instance->_exception( 'Key "' . $key . '" could not be found.' );

		// get current entry
		$entry = $instance->_entries[$key];

		// check if entry should be loaded or reloaded
		if ( ! $entry['loaded'] OR $reload ) {
			if ( $entry['type'] == 'class' ) {
				// get reflection class
				$ref_class = new ReflectionClass( $entry['class'] );
				// create instance
				$entry['value'] = $ref_class->newInstanceArgs( $entry['args'] );
			} else if ( $entry['type'] == 'callback' ) {
				// run callback and set return value
				$entry['value'] = call_user_func_array( $entry['callback'], $entry['args'] );
			} else {
				$instance->_exception( 'Type "' . $type . '" is not supported.' );
			}

			// set (new) value and change "loaded" setting
			$instance->_entries[$key]['value'] = $entry['value'];
			$instance->_entries[$key]['loaded'] = TRUE;
		}

		return $entry['value'];
	}

	/**
	 * Set value of given key
	 * @param string  $key
	 * @param mixed   $value
	 * @param boolean $overwrite  optional, when set will ignore the default overwrite setting
	 * @return boolean  value was set succesfully
	 */
	public static function set( $key, $value, $overwrite = NULL ) {
		// set normal value settings
		$settings = array( 'type' => 'value',
							'loaded' => TRUE,
							'value' => $value );

		return self::get_instance()->_set( $key, $settings, $overwrite );
	}

	/**
	 * Set lazy entry of a class. Instance will only be created when entry
	 * is requested using the get method.
	 * @param string  $key
	 * @param string  $class
	 * @param array   $args
	 * @param boolean $overwrite  optional, when set will ignore the default overwrite setting
	 * @return boolean  value was set succesfully
	 */
	public static function set_lazy_class( $key, $class, $args = array(), $overwrite = NULL ) {
		// set lazy class settings
		$settings = array( 'type' => 'class',
							'class' => $class,
							'args' => $args,
							'loaded' => FALSE,
							'value' => NULL );

		return self::get_instance()->_set( $key, $settings, $overwrite );
	}

	/**
	 * Set lazy entry of a callback function.Function will only be called when entry
	 * is requested using the get method.
	 * @param string  $key
	 * @param array   $callback
	 * @param array   $args
	 * @param boolean $overwrite  optional, when set will ignore the default overwrite setting
	 * @return boolean  value was set succesfully
	 */
	public static function set_lazy_callback( $key, $callback, $args = array(), $overwrite = NULL ) {
		// set lazy callback settings
		$settings = array( 'type' => 'callback',
							'callback' => $callback,
							'args' => $args,
							'loaded' => FALSE,
							'value' => NULL );

		return self::get_instance()->_set( $key, $settings, $overwrite );
	}

	/**
	 * Check if given entry exists
	 * @param string $key
	 * @return boolean
	 */
	public static function has( $key ) {
		return key_exists( $key, self::get_instance()->_entries );
	}

	/**
	 * Check if given (lazy) entry is already loaded
	 * @param string $key
	 * @return boolean
	 */
	public static function is_loaded( $key ) {
		return ( self::has( $key ) AND self::get_instance()->_entries[$key]['loaded'] === TRUE );
	}

	/**
	 * Remove the given entry
	 * @param string $key
	 */
	public static function remove( $key ) {
		if ( ! self::has( $key ) )
			self::get_instance()->_exception( 'Key "' . $key . '"does not exist.' );

		unset( self::get_instance()->_entries[$key] );
	}

	/**
	 * Set default overwriting entries when being set more than once.
	 * @param boolean|NULL $overwrite  optional, if empty can be used as a getter
	 * @return boolean
	 */
	public static function default_overwrite( $overwrite = NULL ) {
		if ( $overwrite !== NULL )
			self::get_instance()->_default_overwrite = (bool) $overwrite;

		return self::get_instance()->_default_overwrite;
	}

	/**
	 * Set value of given key (private use)
	 * @param string  $key
	 * @param mixed   $settings
	 * @param boolean $overwrite  optional, when set will ignore the default overwrite setting
	 * @return boolean  value was set succesfully
	 */
	protected function _set( $key, $settings, $overwrite = NULL ) {
		$instance = self::get_instance();

		// check if overwriting is allowed
		$overwrite = ( $overwrite === NULL )
					? $this->_default_overwrite
					: $overwrite;

		// check if entry exists and overwriting is allowed
		if ( key_exists( $key, $this->_entries ) AND ! $overwrite )
			return FALSE;

		$this->_entries[$key] = $settings;

		return TRUE;
	}

	/**
	 * Throw an exception
	 * @param string $message
	 */
	protected function _exception( $message ) {
		throw new Exception( 'LRegistry: ' . $message );
	}

}

/*?> // ommit closing tag, to prevent unwanted whitespace at the end of the parts generated by the included files */