traderinteractive / memoize
A library for memoizing repeated function calls.
Installs: 73 845
Dependents: 0
Suggesters: 0
Security: 0
Stars: 42
Watchers: 24
Forks: 11
Open Issues: 1
Requires
- php: ^7.0 || ^8.0
Requires (Dev)
- php-coveralls/php-coveralls: ^1.0
- phpunit/phpunit: ^6.0 || ^7.0 || ^8.0 || ^9.0
- predis/predis: ^1.0
- squizlabs/php_codesniffer: ^3.2
Suggests
- predis/predis: Allows for Redis-based memoization.
README
A PHP library for memoizing repeated function calls.
Requirements
This library requires PHP 7.0, or newer.
Installation
This package uses composer so you can just add
traderinteractive/memoize
as a dependency to your composer.json
file.
Memoization
Memoization is a way of optimizing a function that is called repeatedly by caching the results of a function call.
Memoization Providers
This library includes several built-in providers for memoization. Each one
implements the \TraderInteractive\Memoize\Memoize
interface:
interface Memoize { /** * Gets the value stored in the cache or uses the passed function to * compute the value and save to cache. * * @param string $key The key to fetch * @param callable $compute A function to run if the value was not cached * that will return the result. * @param int $cacheTime The number of seconds to cache the response for, * or null to not expire it ever. * @return mixed The data requested, optionally pulled from cache */ public function memoizeCallable($key, $compute, $cacheTime = null); }
The $compute
callable must not take any parameters - if you need parameters,
consider wrapping your function in a closure that pulls the required parameters
into scope. For example, given the function:
$getUser = function($database, $userId) { $query = $database->select('*')->from('user')->where(['id' => $userId]); return $query->fetchOne(); };
You could wrap this in a closure like so:
$getLoggedInUser = function() use($database, $loggedInUserId, $getUser) { return $getUser($database, $loggedInUserId); }; $memoize->memoizeCallable("getUser-{$loggedInUserId}", $getLoggedInUser);
Alternatively, you could invert this and return the closure instead, like so:
$getUserLocator = function($database, $userId) use($getUser) { return function() use($database, $userId, $getUser) { return $getUser($database, $userId); }; }; $getLoggedInUser = $getUserLocator($database, $loggedInUserId); $memoize->memoizeCallable("getUser-{$loggedInUserId}", $getLoggedInUser);
Future versions of this library may add support for parameters, as it can be a common usecase (especially when it comes to recursive functions.
Also worth noting, is that you need to make sure you define your cache keys uniquely for anything using the memoizer.
Predis
The predis provider uses the predis library to
cache the results in Redis. It supports the $cacheTime
parameter so that
results can be recomputed after the time expires.
This memoizer can be used in a way that makes it persistent between processes rather than only caching computation for the current process.
Example
$predis = new \Predis\Client($redisUrl); $memoize = new \TraderInteractive\Memoize\Predis($predis); $compute = function() { // Perform some long operation that you want to memoize }; // Cache he results of $compute for 1 hour. $result = $memoize->memoizeCallable('myLongOperation', $compute, 3600);
Memory
This is a standard in-memory memoizer. It does not support $cacheTime
at the
moment and only keeps the results around as long as the memoizer is in memory.
Example
$memoize = new \TraderInteractive\Memoize\Memory(); $compute = function() { // Perform some long operation that you want to memoize }; $result = $memoize->memoizeCallable('myLongOperation', $compute);
None
This memoizer does not actually memoize anything - it always calls the
$compute
function. It is useful for testing and can also be used when you
disable memoization for debugging, etc. because you can swap your real memoizer
out for this one and everything will still work.
Example
$memoize = new \TraderInteractive\Memoize\None(); $compute = function() { // Perform some long operation that you want to memoize }; // This will never actually memoize the results - they will be recomputed every // time. $result = $memoize->memoizeCallable('myLongOperation', $compute);