Created
August 28, 2014 13:51
-
-
Save meglio/b843177978b4d50ef343 to your computer and use it in GitHub Desktop.
Simple but powerful class that allows for easy static and per-instance parametrized lazy value storage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace _\lang; | |
use ReflectionFunction; | |
use RuntimeException; | |
/** | |
* 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