Skip to content

Instantly share code, notes, and snippets.

@meglio
Last active November 24, 2015 02:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save meglio/8691859 to your computer and use it in GitHub Desktop.
Save meglio/8691859 to your computer and use it in GitHub Desktop.
<?php
/**
* Trait Lazy
*
* Allows for static and dynamic lazy initialization.
* NB. Include "use Lazy;" in every class you want this functionality, otherwise collision may happen if any of parents use Lazy.
*
* Example:
*
* class Test {
* use Lazy;
*
* // The name of the functions, i.e. 'x' and 'y', will be used as a key for the storage of initialized values
*
* function x() { return $this->lazy( function(){ return 'heavy-computation'; } ); }
*
* static function y() { return self::lazyStatic( function(){ return 'heavy-computation'; } ); }
*
* // Calculate lazily for every unique combination of $p1 and $p2
* function f($p1, $p2) { return $this->lazy( function()use($p1, $p2){ return 'computation involving p1 and p2'; } ); }
* }
*/
trait Lazy
{
private $__lazilyInitialized = [];
private static $__lazilyInitializedStatic = [];
private static function __initializeLazily(&$storage, callable $initializer)
{
# Function name which calls $this->lazy() or self::lazyStatic()
$key = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];
# Static variables of the $initializer closure
$params = (new ReflectionFunction($initializer))->getStaticVariables();
if (!is_array($params))
$params = [];
if ($paramsCount = count($params))
$key .= ' :' . $paramsCount . ' ' . serialize($params);
if (!array_key_exists($key, $storage))
{
if (is_callable($initializer))
$storage[$key] = call_user_func($initializer);
else
throw new RuntimeException('$initializer is not callable');
}
return $storage[$key];
}
/**
* @param callback $initializer
* @return mixed
*/
protected function lazy(callable $initializer)
{
return self::__initializeLazily($this->__lazilyInitialized, $initializer);
}
/**
* @param $initializer
* @return mixed
*/
protected static function lazyStatic(callable $initializer)
{
return self::__initializeLazily(self::$__lazilyInitializedStatic, $initializer);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment