-
Notifications
You must be signed in to change notification settings - Fork 12
Add memcache memoize support #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
chrisryan
merged 17 commits into
traderinteractive:master
from
s-sathish:master-memcache
Apr 21, 2025
Merged
Changes from 14 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
6fee3ea
Add memcache memoize support.
s-sathish 1cb275f
Use star for ext-memcache in composer.json
s-sathish ae8a491
Add test case for memcache memoize, address review comments.
s-sathish 0541038
Added back ext-json requirement
s-sathish 56380ff
Update travis ci file to enable support for memcache
s-sathish 06d0eb2
Update travis ci file to enable support for memcache
s-sathish c119d44
Remove the config-add command.
s-sathish c914269
Try to install php-memcache extension before_script
s-sathish 8b50ff3
Try to install php-memcache extension before_script
s-sathish 0224353
Try different method to make it work.
s-sathish 338c3bc
Travis file changes.
s-sathish 44ebc38
Merge branch 'traderinteractive:master' into master
s-sathish ecc8795
Changes for build environment fixes
s-sathish f6444e0
Merge branch 'master' into master-memcache
chrisryan 01b9c9d
Update src/Memcache.php
chrisryan a583758
Update tests/MemcacheTest.php
chrisryan eb60f59
Update src/Memcache.php
chrisryan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| extension=memcache.so |
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| extension=memcached.so |
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| <?php | ||
|
|
||
| namespace TraderInteractive\Memoize; | ||
|
|
||
| /** | ||
| * A memoizer that caches the results in memcache. | ||
| */ | ||
| class Memcache implements Memoize | ||
| { | ||
| /** | ||
| * The memcache client | ||
| * | ||
| * @var \Memcache | ||
| */ | ||
| private $client; | ||
|
|
||
| /** | ||
| * Cache refresh | ||
| * | ||
| * @var boolean | ||
| */ | ||
| private $refresh; | ||
|
|
||
| /** | ||
| * Sets the memcache client. | ||
| * | ||
| * @param \Memcache $client The memcache client to use | ||
| * @param boolean $refresh If true we will always overwrite cache even if it is already set | ||
| */ | ||
| public function __construct(\Memcache $client, bool $refresh = false) | ||
| { | ||
| $this->client = $client; | ||
| $this->refresh = $refresh; | ||
| } | ||
|
|
||
| /** | ||
| * The value is stored in memcache as a json_encoded string, | ||
| * so make sure that the value you return from $compute is json-encode-able. | ||
| * | ||
| * @see Memoize::memoizeCallable | ||
| * | ||
| * @param string $key | ||
| * @param callable $compute | ||
| * @param int|null $cacheTime | ||
| * | ||
| * @return mixed | ||
| */ | ||
| public function memoizeCallable(string $key, callable $compute, int $cacheTime = null) | ||
| { | ||
| if (!$this->refresh) { | ||
| try { | ||
| $cached = $this->client->get($key, $flags, $flags); | ||
| if ($cached !== false && $cached != null) { | ||
| $data = json_decode($cached, true); | ||
| return $data['result']; | ||
| } | ||
| } catch (\Exception $e) { | ||
| return call_user_func($compute); | ||
| } | ||
| } | ||
|
|
||
| $result = call_user_func($compute); | ||
|
|
||
| // If the result is false/null/empty, then there is no point in storing it in cache. | ||
| if ($result === false || $result == null || empty($result)) | ||
| return $result; | ||
chrisryan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| $this->cache($key, json_encode(['result' => $result]), $cacheTime); | ||
|
|
||
| return $result; | ||
| } | ||
|
|
||
| /** | ||
| * Caches the value into memcache with errors suppressed. | ||
| * | ||
| * @param string $key The key. | ||
| * @param string $value The value. | ||
| * @param int $cacheTime The optional cache time | ||
| * | ||
| * @return void | ||
| */ | ||
| private function cache(string $key, string $value, int $cacheTime = null) | ||
| { | ||
| try { | ||
| $this->client->set($key, $value, 0, $cacheTime); | ||
| } catch (\Exception $e) { | ||
| // We don't want exceptions in accessing the cache to break functionality. | ||
| // The cache should be as transparent as possible. | ||
| // If insight is needed into these exceptions, | ||
| // a better way would be by notifying an observer with the errors. | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| <?php | ||
|
|
||
| namespace TraderInteractive\Memoize; | ||
|
|
||
| use PHPUnit\Framework\TestCase; | ||
|
|
||
| /** | ||
| * @coversDefaultClass \TraderInteractive\Memoize\Memcache | ||
| * @covers ::<private> | ||
| */ | ||
| class MemcacheTest extends TestCase | ||
| { | ||
| /** | ||
| * @test | ||
| * @covers ::__construct | ||
| * @covers ::memoizeCallable | ||
| */ | ||
| public function memoizeCallableWithCachedValue() | ||
| { | ||
| $count = 0; | ||
| $key = 'foo'; | ||
| $value = 'bar'; | ||
| $cachedValue = json_encode(['result' => $value]); | ||
| $compute = function () use (&$count, $value) { | ||
| $count++; | ||
|
|
||
| return $value; | ||
| }; | ||
|
|
||
|
|
||
| $client = $this->getMemcacheMock(); | ||
| $client->expects( | ||
| $this->once() | ||
| )->method('get')->with($this->equalTo($key))->will($this->returnValue($cachedValue)); | ||
|
|
||
| $memoizer = new Memcache($client); | ||
|
|
||
| $this->assertSame($value, $memoizer->memoizeCallable($key, $compute)); | ||
| $this->assertSame(0, $count); | ||
| } | ||
|
|
||
| /** | ||
| * @test | ||
| * @covers ::__construct | ||
| * @covers ::memoizeCallable | ||
| */ | ||
| public function memoizeCallableWithExceptionOnGet() | ||
| { | ||
| $count = 0; | ||
| $key = 'foo'; | ||
| $value = 'bar'; | ||
| $compute = function () use (&$count, $value) { | ||
| $count++; | ||
|
|
||
| return $value; | ||
| }; | ||
|
|
||
| $client = $this->getMemcacheMock(); | ||
| $client->expects( | ||
| $this->once() | ||
| )->method('get')->with($this->equalTo($key))->will($this->throwException(new \Exception())); | ||
|
|
||
| $memoizer = new Memcache($client); | ||
|
|
||
| $this->assertSame($value, $memoizer->memoizeCallable($key, $compute)); | ||
| $this->assertSame(1, $count); | ||
| } | ||
|
|
||
| /** | ||
| * @test | ||
| * @covers ::__construct | ||
| * @covers ::memoizeCallable | ||
| */ | ||
| public function memoizeCallableWithUncachedKey() | ||
| { | ||
| $count = 0; | ||
| $key = 'foo'; | ||
| $value = 'bar'; | ||
| $cachedValue = json_encode(['result' => $value]); | ||
| $cacheTime = 1234; | ||
| $compute = function () use (&$count, $value) { | ||
| $count++; | ||
|
|
||
| return $value; | ||
| }; | ||
|
|
||
| $client = $this->getMemcacheMock(); | ||
| $client->expects($this->once())->method('get')->with($this->equalTo($key))->will($this->returnValue(null)); | ||
| $client->expects($this->once())->method('set')->with($this->equalTo($key), $this->equalTo($cachedValue), $this->equalTo(0), $this->equalTo($cacheTime)); | ||
chrisryan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| $memoizer = new Memcache($client); | ||
|
|
||
| $this->assertSame($value, $memoizer->memoizeCallable($key, $compute, $cacheTime)); | ||
| $this->assertSame(1, $count); | ||
| } | ||
|
|
||
| /** | ||
| * @test | ||
| * @covers ::__construct | ||
| * @covers ::memoizeCallable | ||
| */ | ||
| public function memoizeCallableWithUncachedKeyWithExceptionOnSet() | ||
| { | ||
| $count = 0; | ||
| $key = 'foo'; | ||
| $value = 'bar'; | ||
| $cachedValue = json_encode(['result' => $value]); | ||
| $compute = function () use (&$count, $value) { | ||
| $count++; | ||
|
|
||
| return $value; | ||
| }; | ||
|
|
||
| $client = $this->getMemcacheMock(); | ||
| $client->expects( | ||
| $this->once() | ||
| )->method('get')->with($this->equalTo($key))->will($this->returnValue(null)); | ||
| $setExpectation = $client->expects( | ||
| $this->once() | ||
| )->method('set')->with($this->equalTo($key), $this->equalTo($cachedValue)); | ||
| $setExpectation->will($this->throwException(new \Exception())); | ||
|
|
||
| $memoizer = new Memcache($client); | ||
|
|
||
| $this->assertSame($value, $memoizer->memoizeCallable($key, $compute)); | ||
| $this->assertSame(1, $count); | ||
| } | ||
|
|
||
| public function getMemcacheMock() : \Memcache | ||
| { | ||
| return $this->getMockBuilder('\Memcache')->setMethods(['get', 'set'])->getMock(); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.