Skip to content

Instantly share code, notes, and snippets.

@jeffgca
Created October 7, 2010 05:09
Show Gist options
  • Select an option

  • Save jeffgca/614584 to your computer and use it in GitHub Desktop.

Select an option

Save jeffgca/614584 to your computer and use it in GitHub Desktop.
<?php
interface dRF_Cache_Interface {
public function get($id);
public function getList($ids);
public function set($id, $value);
public function setList($list);
}
abstract class dRF_Cache_Handler {
/* some cache instance, probably Memcached */
protected $_backend;
/* expiration period for the cache */
protected $_expiry;
/* an array of config options */
protected $_config;
public function __construct() {}
public static function getInstance($config) {}
public function get($id) {}
public function getList($ids) {}
public function set($id, $value) {}
public function setList($list) {}
}
class dRF_Cache_Memcached
extends dRF_Cache_Handler
implements dRF_Cache_Interface {
public function __construct($config) {
/* cache the mamcache instance as a static var */
static $memcache = FALSE;
if (is_a($memcache, 'Memcached')) {
$this->_backend = $memcache;
} else {
$this->_backend = new Memcache();
}
}
public static function getInstance($config) {
return new self($config);
}
public function get($id) {
$return = $this->_backend->get($id);
if ($return === FALSE) {
return $this->_getError();
}
else {
return $return;
}
}
public function getList($ids) {
$return = $this->_backend->getMulti($ids);
if ($return === FALSE) {
return $this->_getError();
}
else {
return $return;
}
}
public function set($id, $value, $expiry=FALSE) {
$expiry = $expiry||$this->_expiry;
$return = $this->_backend->set($id, $value, $expiry);
if ($return === FALSE) {
return $this->_getError();
}
else {
return $return;
}
}
public function setList($list, $expiry=FALSE) {
$expiry = $expiry||$this->_expiry;
$return = $this->_backend->setMulti($list, $this->_expiry);
if ($return === FALSE) {
return $this->_getError();
}
else {
return TRUE;
}
}
private function _getError() {
return array(
'code' => $this->_backend->getResultCode(),
'message' => $this->_backend->getResultMessage()
);
}
public function __call($name, $args) {
if (method_exists($this->foo, $name)) {
return call_user_func_array(array($this->foo, $name), $args);
}
}
}
@mostlygeek

Copy link
Copy Markdown

Why use setList() or getList() instead of setMulti() or getMulti()?
Those seem to make more sense to me.

I like this more than Zend_Cache_X type stuff. That cache was designed for caching text only (stupid) but works in a similar fashion.

@mostlygeek

Copy link
Copy Markdown

Did I mention that I think Zend_Cache_X is stupid, i can say that because I wrote a memcached replacement for it that turned out to be stupid. Though I was rather drowsy and it works but still stupid.

Plus it promote code like if (!($data = $cache->get()) ... this is ugly imho. In the Zend_Cache design false is always returned on a cache miss, however, in the rare (useless?) case where you're caching boolean false or 0 or something that results in 'false' this would be strange. .. rambling..

I think...

  1. don't care about the back end (memcache, file, APC, blah)
  2. Easy to implement, i like the factory pattern though this might make it easier to work with:

dRF_Cache_Memcache::setDefaults($config); // optionally done in the bootstrap

$cache = dRF_Cache_Memcache::getInstance(); // just use it. Assume that it is there. throws exception if no defaults. always returns the same default instantiated object, not a new one.

$cache = dRF_Cache_Memcache::getInstance($config); // a custom one... always return a new instance.

  1. cache misses are easy to detect (returns NULL?)

$cache = dRF_Cache_Memcache::getInstance();
$data = $cache->get('someKey');
if (is_null($data)) {
// cache miss...
}

maybe something completely stupid...

$data = $cache->get('someKey', function() {
// holy shit! ... a callback on cache miss :b .
// i wonder how closures are in PHP...
});

@jeffgca

jeffgca commented Oct 7, 2010

Copy link
Copy Markdown
Author

I like the semantics of get/set List better than 'multi'. You could implement an APC or Redis backend for this just as easily and the interface as-is makes more sens to me.

Note the implementation of __call(), allows you to call functions as-is on the underlying backend unless the class itself overrides them. I thought that was a neat trick.;)

@jeffgca

jeffgca commented Oct 7, 2010

Copy link
Copy Markdown
Author

Also, return values could be wrapped in an array with an error key to check? I like to return types consistently for something this low level, eg always return an array, and have that array be something you can inspect to get errors or pass onward results.

@mostlygeek

Copy link
Copy Markdown

__call() very neat trick. I think I would prefer $cache->backend()->method() pattern. It is clearer on what's going on.

Unlike always returning an array. No question then, if cache hit array, else null.

@jeffgca

jeffgca commented Oct 7, 2010

Copy link
Copy Markdown
Author

he one side of the debate is, if you return null, it's unambiguousthat the call failed. On the other hand, you don't know why the call failed. Returning the results of _getError() however always gives the client code something to log or raise as a n exception.

@mostlygeek

Copy link
Copy Markdown

For something like $cache->get(), if there was an error, like couldn't connect to memcache or something like that it shouldn't affect the fact that $cache->get() returned null. It should be $data or null.

If we need to debug why the cache is failing then that should be in a check script so...

$cache->set('data', $data);
if (is_null($cache->get('data'))) {
// failed ... alert somebody or do something as the cache is not working
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment