Skip to content

Commit f2506fb

Browse files
author
Spencer Rinehart
committed
Initial commit with a Null, Memory, and Predis provider.
0 parents  commit f2506fb

15 files changed

Lines changed: 1284 additions & 0 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/clover.xml
2+
/coverage/
3+
/vendor/

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
language: php
2+
php:
3+
- 5.6
4+
- 5.5
5+
- 5.4
6+
- 5.3
7+
script: ./build.php

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Dominion Enterprises
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Memoize
2+
A PHP library for memoizing repeated function calls.
3+
4+
## Requirements
5+
This library requires PHP 5.3, or newer.
6+
7+
## Installation
8+
This package uses [composer](https://getcomposer.org) so you can just add
9+
`dominionenterprises/memoize` as a dependency to your `composer.json` file.
10+
11+
## Memoization
12+
[Memoization](http://en.wikipedia.org/wiki/Memoization) is a way of optimizing a function that is called repeatedly by caching the results of a function call.
13+
14+
## Memoization Providers
15+
This library includes several built-in providers for memoization. Each one
16+
implements the `\DominionEnterprises\Memoize\Memoize` interface:
17+
```php
18+
interface Memoize
19+
{
20+
/**
21+
* Gets the value stored in the cache or uses the passed function to
22+
* compute the value and save to cache.
23+
*
24+
* @param string $key The key to fetch
25+
* @param callable $compute A function to run if the value was not cached
26+
* that will return the result.
27+
* @param int $cacheTime The number of seconds to cache the response for,
28+
* or null to not expire it ever.
29+
* @return mixed The data requested, optionally pulled from cache
30+
*/
31+
public function memoizeCallable($key, $compute, $cacheTime = null);
32+
}
33+
```
34+
35+
The `$compute` callable must not take any parameters - if you need parameters,
36+
consider wrapping your function in a closure that pulls the required parameters
37+
into scope. For example, given the function:
38+
```php
39+
$getUser = function($database, $userId) {
40+
$query = $database->select('*')->from('user')->where(['id' => $userId]);
41+
return $query->fetchOne();
42+
};
43+
```
44+
45+
You could wrap this in a closure like so:
46+
```php
47+
$getLoggedInUser = function() use($database, $loggedInUserId, $getUser) {
48+
return $getUser($database, $loggedInUserId);
49+
};
50+
51+
$memoize->memoizeCallable("getUser-{$loggedInUserId}", $getLoggedInUser);
52+
```
53+
54+
Future versions of this library may add support for parameters, as it can be a
55+
common usecase (especially when it comes to recursive functions.
56+
57+
Also worth noting, is that you need to make sure you define your cache keys
58+
uniquely for anything using the memoizer.
59+
60+
### Predis
61+
The predis provider uses the [predis](https://github.com/nrk/predis) library to
62+
cache the results in Redis. It supports the `$cacheTime` parameter so that
63+
results can be recomputed after the time expires.
64+
65+
This memoizer can be used in a way that makes it persistent between processes
66+
rather than only caching computation for the current process.
67+
68+
#### Example
69+
```php
70+
$predis = new \Predis\Client($redisUrl);
71+
$memoize = new \DominionEnterprises\Memoize\Predis($predis);
72+
73+
$compute = function() {
74+
// Perform some long operation that you want to memoize
75+
};
76+
77+
// Cache he results of $compute for 1 hour.
78+
$result = $memoize->memoizeCallable('myLongOperation', $compute, 3600);
79+
```
80+
81+
### Memory
82+
This is a standard in-memory memoizer. It does not support `$cacheTime` at the
83+
moment and only keeps the results around as long as the memoizer is in memory.
84+
85+
#### Example
86+
```php
87+
$memoize = new \DominionEnterprises\Memoize\Memory();
88+
89+
$compute = function() {
90+
// Perform some long operation that you want to memoize
91+
};
92+
93+
$result = $memoize->memoizeCallable('myLongOperation', $compute);
94+
```
95+
96+
### Null
97+
This memoizer does not actually memoize anything - it always calls the
98+
`$compute` function. It is useful for testing and can also be used when you
99+
disable memoization for debugging, etc. because you can swap your real memoizer
100+
out for this one and everything will still work.
101+
102+
#### Example
103+
```php
104+
$memoize = new \DominionEnterprises\Memoize\Null();
105+
106+
$compute = function() {
107+
// Perform some long operation that you want to memoize
108+
};
109+
110+
// This will never actually memoize the results - they will be recomputed every
111+
// time.
112+
$result = $memoize->memoizeCallable('myLongOperation', $compute);
113+
```

build.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env php
2+
<?php
3+
chdir(__DIR__);
4+
5+
$returnStatus = null;
6+
passthru('composer install --dev', $returnStatus);
7+
if ($returnStatus !== 0) {
8+
exit(1);
9+
}
10+
11+
passthru('./vendor/bin/phpcs --standard=PSR1 -n src tests *.php', $returnStatus);
12+
if ($returnStatus !== 0) {
13+
exit(1);
14+
}
15+
16+
passthru('./vendor/bin/phpunit --coverage-html coverage --coverage-clover clover.xml --strict tests', $returnStatus);
17+
if ($returnStatus !== 0) {
18+
exit(1);
19+
}
20+
21+
$xml = new SimpleXMLElement(file_get_contents('clover.xml'));
22+
foreach ($xml->xpath('//file/metrics') as $metric) {
23+
if ((int)$metric['elements'] !== (int)$metric['coveredelements']) {
24+
file_put_contents('php://stderr', "Code coverage was NOT 100%\n");
25+
exit(1);
26+
}
27+
}
28+
29+
echo "Code coverage was 100%\n";

composer.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "dominionenterprises/memoize",
3+
"description": "A library for memoizing repeated function calls.",
4+
"keywords": ["memoization", "predis", "cache", "optimization"],
5+
"authors": [
6+
{
7+
"name": "Spencer Rinehart",
8+
"email": "anubis@overthemonkey.com",
9+
"role": "Developer"
10+
}
11+
],
12+
"license": "MIT",
13+
"require": {
14+
"php": ">=5.3.2"
15+
},
16+
"require-dev": {
17+
"predis/predis": "~0.8.4",
18+
"phpunit/phpunit": "~4.0",
19+
"squizlabs/php_codesniffer": "~1.5",
20+
"lib-libxml": "*"
21+
},
22+
"suggest": {
23+
"predis/predis": "Allows for Redis-based memoization."
24+
},
25+
"autoload": {
26+
"psr-4": { "DominionEnterprises\\Memoize\\": "src/" }
27+
}
28+
}

0 commit comments

Comments
 (0)