Skip to content

Instantly share code, notes, and snippets.

@jjt
Created November 25, 2011 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jjt/1394482 to your computer and use it in GitHub Desktop.
Save jjt/1394482 to your computer and use it in GitHub Desktop.
Arbitrary redis caching of output and serializable objects
<?php
// Needs a global $redis_config
function get_redis($force=false) {
global $redis_config,$redis_instance;
if(!is_object($redis_config))
die("Couldn't find \$redis_config or it's not an object!");
// No redis? No problem!
if(!class_exists('Redis') || !extension_loaded('redis')) {
$redis_instance = new Fake_Redis();
return $redis_instance;
}
if(!$redis_instance || $force !== false) {
$redis_instance = new Redis();
$redis_ip = $redis_config->ip;
if(!$redis_ip)
$redis_ip = 'localhost';
$redis_instance->connect($redis_ip);
// Let's keep the redis databases separate!
if(!isset($redis_config->db_id))
die('Warning! No redis db selected');
else
$redis_instance->select($redis_config->db_id);
}
return $redis_instance;
}
// Base class for a cached object, represents one redis entry
class Redis_Cache {
var $key_prefix = '';
function __construct($user_key,$opts='') {
$default_opts = array(
'output_cache' => true,
'profile' => false,
'profile_noisy' => true,
'expires' => false
);
$this->opts = array_merge($default_opts,(array)$opts);
if(isset($_GET['redis_debug']))
$this->opts['profile'] = true;
// We add info to our keys
$this->user_key = $user_key;
$this->key = $user_key;
if($this->key_prefix !== '')
$this->key = "$this->key_prefix:$this->key";
$this->redis = get_redis();
$this->cache = $this->redis->get($this->key);
// Bust the cache!
if(isset($_GET['redis_bust']))
$this->cache = false;
$this->cache_hit = $this->cache !== false;
$this->cache_miss = !$this->cache_hit;
$this->cache_hit_str = $this->cache !== false ? 'hit' : 'miss';
}
function write_cache($val,$expires=false) {
if(!$expires)
$expires = $this->opts['expires'];
if($expires)
return $this->redis->setex($this->key,$expires,$val);
$this->redis->set($this->key,$val);
}
function profile_start($noisy=true) {
if(!$this->opts['profile'])
return;
$this->time_start = microtime(true);
if($noisy && $this->opts['profile_noisy'])
echo "\n\n<!-- REDIS BEGIN: $this->user_key, $this->cache_hit_str -->\n\n";
}
function profile_end($noisy=true) {
if(!$this->opts['profile'])
return;
$this->time_end = microtime(true);
$this->time_delta = round($this->time_end - $this->time_start,5);
if($noisy && $this->opts['profile_noisy'])
echo "\n\n<!-- REDIS END: $this->user_key, $this->cache_hit_str, $this->time_delta -->\n\n";
}
}
// Redis output buffering for caching arbitrary output
// You have to do the (strict) checking yourself:
//
// $rob = new Redis_OB('my-key');
// if($rob->cache === false)
// ... your code ...
// $rob->output();
class Redis_Cache_OB extends Redis_Cache {
var $key_prefix = 'Cache_OB';
function __construct($key,$opts='') {
parent::__construct($key,$opts);
$this->profile_start();
if($this->cache_miss)
ob_start();
}
function end() {
if($this->cache_miss) {
$this->cache = ob_get_clean();
$this->write_cache($this->cache);
}
}
function output() {
$this->end();
if($this->opts['output_cache'])
echo $this->cache;
$this->profile_end();
}
}
// Makes a one liner out of the caching process
// You can pass through a string with a function name, or an anonymous function
// Optional args array for the called fn
class Redis_Cache_OB_Func extends Redis_Cache_OB {
function __construct($key,$func,$args=false,$opts='') {
parent::__construct($key,$opts);
if($this->cache_miss) {
if($args !== false && is_array($args))
call_user_func_array($func,$args);
else
call_user_func($func);
}
$this->output();
}
}
// Caching a php variable through serialize()
class Redis_Cache_Var extends Redis_Cache {
var $key_prefix = 'Cache_Var';
}
// Since we can't delay instantiation of a new object at call time, we have to wrap it in a callback function that returns the new object
// We could do it with new Redis_Cache_Var('key','class_name',array('constructor','params')) but anon fns are more flexible
//
// Before caching:
// $my_obj = new MyObj();
// After caching:
// $my_obj = redis_cache_var('my_obj',function(){
// return new MyObj();
// });
//
function redis_cache_var($key,$cb_func,$opts='') {
$rcv = new Redis_Cache_Var($key,$opts);
$rcv->profile_start();
if($rcv->cache_hit)
$obj = unserialize($rcv->cache);
else {
$obj = $cb_func();
$rcv->write_cache(serialize($obj));
}
$rcv->profile_end();
return $obj;
}
// Allows us silent redis errors in case we don't have it
class Fake_Redis {
// Need to have some way of telling if we're a dirty faker!
var $is_fake_redis = true;
// Stubbbbzz
function connect($a='',$b='',$c='',$d='',$e='') { return false; }
function pconnect($a='',$b='',$c='',$d='',$e='') { return false; }
function close($a='',$b='',$c='',$d='',$e='') { return false; }
function ping($a='',$b='',$c='',$d='',$e='') { return false; }
function get($a='',$b='',$c='',$d='',$e='') { return false; }
function set($a='',$b='',$c='',$d='',$e='') { return false; }
function setex($a='',$b='',$c='',$d='',$e='') { return false; }
function setnx($a='',$b='',$c='',$d='',$e='') { return false; }
function getSet($a='',$b='',$c='',$d='',$e='') { return false; }
function randomKey($a='',$b='',$c='',$d='',$e='') { return false; }
function renameKey($a='',$b='',$c='',$d='',$e='') { return false; }
function renameNx($a='',$b='',$c='',$d='',$e='') { return false; }
function getMultiple($a='',$b='',$c='',$d='',$e='') { return false; }
function exists($a='',$b='',$c='',$d='',$e='') { return false; }
function delete($a='',$b='',$c='',$d='',$e='') { return false; }
function incr($a='',$b='',$c='',$d='',$e='') { return false; }
function incrBy($a='',$b='',$c='',$d='',$e='') { return false; }
function decr($a='',$b='',$c='',$d='',$e='') { return false; }
function decrBy($a='',$b='',$c='',$d='',$e='') { return false; }
function type($a='',$b='',$c='',$d='',$e='') { return false; }
function append($a='',$b='',$c='',$d='',$e='') { return false; }
function getRange($a='',$b='',$c='',$d='',$e='') { return false; }
function setRange($a='',$b='',$c='',$d='',$e='') { return false; }
function getBit($a='',$b='',$c='',$d='',$e='') { return false; }
function setBit($a='',$b='',$c='',$d='',$e='') { return false; }
function strlen($a='',$b='',$c='',$d='',$e='') { return false; }
function getKeys($a='',$b='',$c='',$d='',$e='') { return false; }
function sort($a='',$b='',$c='',$d='',$e='') { return false; }
function sortAsc($a='',$b='',$c='',$d='',$e='') { return false; }
function sortAscAlpha($a='',$b='',$c='',$d='',$e='') { return false; }
function sortDesc($a='',$b='',$c='',$d='',$e='') { return false; }
function sortDescAlpha($a='',$b='',$c='',$d='',$e='') { return false; }
function lPush($a='',$b='',$c='',$d='',$e='') { return false; }
function rPush($a='',$b='',$c='',$d='',$e='') { return false; }
function lPushx($a='',$b='',$c='',$d='',$e='') { return false; }
function rPushx($a='',$b='',$c='',$d='',$e='') { return false; }
function lPop($a='',$b='',$c='',$d='',$e='') { return false; }
function rPop($a='',$b='',$c='',$d='',$e='') { return false; }
function blPop($a='',$b='',$c='',$d='',$e='') { return false; }
function brPop($a='',$b='',$c='',$d='',$e='') { return false; }
function lSize($a='',$b='',$c='',$d='',$e='') { return false; }
function lRemove($a='',$b='',$c='',$d='',$e='') { return false; }
function listTrim($a='',$b='',$c='',$d='',$e='') { return false; }
function lGet($a='',$b='',$c='',$d='',$e='') { return false; }
function lGetRange($a='',$b='',$c='',$d='',$e='') { return false; }
function lSet($a='',$b='',$c='',$d='',$e='') { return false; }
function lInsert($a='',$b='',$c='',$d='',$e='') { return false; }
function sAdd($a='',$b='',$c='',$d='',$e='') { return false; }
function sSize($a='',$b='',$c='',$d='',$e='') { return false; }
function sRemove($a='',$b='',$c='',$d='',$e='') { return false; }
function sMove($a='',$b='',$c='',$d='',$e='') { return false; }
function sPop($a='',$b='',$c='',$d='',$e='') { return false; }
function sRandMember($a='',$b='',$c='',$d='',$e='') { return false; }
function sContains($a='',$b='',$c='',$d='',$e='') { return false; }
function sMembers($a='',$b='',$c='',$d='',$e='') { return false; }
function sInter($a='',$b='',$c='',$d='',$e='') { return false; }
function sInterStore($a='',$b='',$c='',$d='',$e='') { return false; }
function sUnion($a='',$b='',$c='',$d='',$e='') { return false; }
function sUnionStore($a='',$b='',$c='',$d='',$e='') { return false; }
function sDiff($a='',$b='',$c='',$d='',$e='') { return false; }
function sDiffStore($a='',$b='',$c='',$d='',$e='') { return false; }
function setTimeout($a='',$b='',$c='',$d='',$e='') { return false; }
function save($a='',$b='',$c='',$d='',$e='') { return false; }
function bgSave($a='',$b='',$c='',$d='',$e='') { return false; }
function lastSave($a='',$b='',$c='',$d='',$e='') { return false; }
function flushDB($a='',$b='',$c='',$d='',$e='') { return false; }
function flushAll($a='',$b='',$c='',$d='',$e='') { return false; }
function dbSize($a='',$b='',$c='',$d='',$e='') { return false; }
function auth($a='',$b='',$c='',$d='',$e='') { return false; }
function ttl($a='',$b='',$c='',$d='',$e='') { return false; }
function persist($a='',$b='',$c='',$d='',$e='') { return false; }
function info($a='',$b='',$c='',$d='',$e='') { return false; }
function resetStat($a='',$b='',$c='',$d='',$e='') { return false; }
function select($a='',$b='',$c='',$d='',$e='') { return false; }
function move($a='',$b='',$c='',$d='',$e='') { return false; }
function bgrewriteaof($a='',$b='',$c='',$d='',$e='') { return false; }
function slaveof($a='',$b='',$c='',$d='',$e='') { return false; }
function object($a='',$b='',$c='',$d='',$e='') { return false; }
function mset($a='',$b='',$c='',$d='',$e='') { return false; }
function msetnx($a='',$b='',$c='',$d='',$e='') { return false; }
function rpoplpush($a='',$b='',$c='',$d='',$e='') { return false; }
function brpoplpush($a='',$b='',$c='',$d='',$e='') { return false; }
function zAdd($a='',$b='',$c='',$d='',$e='') { return false; }
function zDelete($a='',$b='',$c='',$d='',$e='') { return false; }
function zRange($a='',$b='',$c='',$d='',$e='') { return false; }
function zReverseRange($a='',$b='',$c='',$d='',$e='') { return false; }
function zRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; }
function zRevRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; }
function zCount($a='',$b='',$c='',$d='',$e='') { return false; }
function zDeleteRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; }
function zDeleteRangeByRank($a='',$b='',$c='',$d='',$e='') { return false; }
function zCard($a='',$b='',$c='',$d='',$e='') { return false; }
function zScore($a='',$b='',$c='',$d='',$e='') { return false; }
function zRank($a='',$b='',$c='',$d='',$e='') { return false; }
function zRevRank($a='',$b='',$c='',$d='',$e='') { return false; }
function zInter($a='',$b='',$c='',$d='',$e='') { return false; }
function zUnion($a='',$b='',$c='',$d='',$e='') { return false; }
function zIncrBy($a='',$b='',$c='',$d='',$e='') { return false; }
function expireAt($a='',$b='',$c='',$d='',$e='') { return false; }
function hGet($a='',$b='',$c='',$d='',$e='') { return false; }
function hSet($a='',$b='',$c='',$d='',$e='') { return false; }
function hSetNx($a='',$b='',$c='',$d='',$e='') { return false; }
function hDel($a='',$b='',$c='',$d='',$e='') { return false; }
function hLen($a='',$b='',$c='',$d='',$e='') { return false; }
function hKeys($a='',$b='',$c='',$d='',$e='') { return false; }
function hVals($a='',$b='',$c='',$d='',$e='') { return false; }
function hGetAll($a='',$b='',$c='',$d='',$e='') { return false; }
function hExists($a='',$b='',$c='',$d='',$e='') { return false; }
function hIncrBy($a='',$b='',$c='',$d='',$e='') { return false; }
function hMset($a='',$b='',$c='',$d='',$e='') { return false; }
function hMget($a='',$b='',$c='',$d='',$e='') { return false; }
function multi($a='',$b='',$c='',$d='',$e='') { return false; }
function discard($a='',$b='',$c='',$d='',$e='') { return false; }
function exec($a='',$b='',$c='',$d='',$e='') { return false; }
function pipeline($a='',$b='',$c='',$d='',$e='') { return false; }
function watch($a='',$b='',$c='',$d='',$e='') { return false; }
function unwatch($a='',$b='',$c='',$d='',$e='') { return false; }
function publish($a='',$b='',$c='',$d='',$e='') { return false; }
function subscribe($a='',$b='',$c='',$d='',$e='') { return false; }
function unsubscribe($a='',$b='',$c='',$d='',$e='') { return false; }
function getOption($a='',$b='',$c='',$d='',$e='') { return false; }
function setOption($a='',$b='',$c='',$d='',$e='') { return false; }
function open($a='',$b='',$c='',$d='',$e='') { return false; }
function popen($a='',$b='',$c='',$d='',$e='') { return false; }
function lLen($a='',$b='',$c='',$d='',$e='') { return false; }
function sGetMembers($a='',$b='',$c='',$d='',$e='') { return false; }
function mget($a='',$b='',$c='',$d='',$e='') { return false; }
function expire($a='',$b='',$c='',$d='',$e='') { return false; }
function zunionstore($a='',$b='',$c='',$d='',$e='') { return false; }
function zinterstore($a='',$b='',$c='',$d='',$e='') { return false; }
function zRemove($a='',$b='',$c='',$d='',$e='') { return false; }
function zRem($a='',$b='',$c='',$d='',$e='') { return false; }
function zRemoveRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; }
function zRemRangeByScore($a='',$b='',$c='',$d='',$e='') { return false; }
function zRemRangeByRank($a='',$b='',$c='',$d='',$e='') { return false; }
function zSize($a='',$b='',$c='',$d='',$e='') { return false; }
function substr($a='',$b='',$c='',$d='',$e='') { return false; }
function rename($a='',$b='',$c='',$d='',$e='') { return false; }
function del($a='',$b='',$c='',$d='',$e='') { return false; }
function keys($a='',$b='',$c='',$d='',$e='') { return false; }
function lrem($a='',$b='',$c='',$d='',$e='') { return false; }
function ltrim($a='',$b='',$c='',$d='',$e='') { return false; }
function lindex($a='',$b='',$c='',$d='',$e='') { return false; }
function lrange($a='',$b='',$c='',$d='',$e='') { return false; }
function scard($a='',$b='',$c='',$d='',$e='') { return false; }
function srem($a='',$b='',$c='',$d='',$e='') { return false; }
function sismember($a='',$b='',$c='',$d='',$e='') { return false; }
function zrevrange($a='',$b='',$c='',$d='',$e='') { return false; }
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment