| <?php | 
|   | 
| /** | 
|  * Redis 拓展类 | 
|  * @author: 喵了个咪 <wenzhenxi@vip.qq.com> 2015-11-15 | 
|  * | 
|  * @author: Axios <axioscros@aliyun.com> 2016-09-01 | 
|  * | 
|  * @update 2016-09-01 | 
|  * 1. 增加__call魔术方法,重载当前类中方法,统一切换DB,缩减代码行数,减少类中方法互相调用时,重复切换DB | 
|  * 2. 增加save_time方法,更新具有有效时间key的value,并且不重置有效时间,使用方式: DI()->redis->save_time($key, $value,$dbname); | 
|  * 3. 增加counter_forever方法,永久计数器,每次调用递增1,使用方式: DI()->redis->counter_forever($key,$dbname); | 
|  * 4. 增加counter_time_create方法,创建临时计数器,每次调用重置计数器和有效时间,使用方式: DI()->redis->counter_time_create($key,$expire,$dbname); | 
|  * 5. 增加counter_time_update方法,更新临时计数器,每次调用递增1,使用方式: DI()->redis->counter_time_update($key,$dbname); | 
|  * 6. 修复一处bug,get_time_ttl方法中,$this->unformatValue($value)修改为$value。修改前,调用此方法,会一直回调false | 
|  * | 
|  */ | 
| class Redis_Lite extends PhalApi_Cache_Redis{ | 
|   | 
|     private $db_old; | 
|   | 
|     /** | 
|      * 重载方法,统一切换DB | 
|      * | 
|      * @param $name | 
|      * @param $arguments | 
|      * @return mixed | 
|      * | 
|      * @author: Axios <axioscros@aliyun.com> 2016-09-01 | 
|      */ | 
|     public function __call($name, $arguments) | 
|     { | 
|         $last = count($arguments)-1; | 
|         $dbname = $arguments[$last]; | 
|         $this->switchDB($dbname); | 
|         unset($arguments[$last]); | 
|         $arguments = empty($arguments)? array():$arguments; | 
|         return call_user_func_array(array($this,$name),$arguments); | 
|     } | 
|   | 
|     //---------------------------------------------------string类型------------------------------------------------- | 
|     /** | 
|      * 将value 的值赋值给key,生存时间为永久 并根据名称自动切换库 | 
|      */ | 
|     protected function set_forever($key, $value){ | 
|         return $this->redis->set($this->formatKey($key), $this->formatValue($value)); | 
|     } | 
|   | 
|     /** | 
|      * 获取value 并根据名称自动切换库 | 
|      */ | 
|     protected function get_forever($key){ | 
|         $value = $this->redis->get($this->formatKey($key)); | 
|         return $value !== FALSE ? $this->unformatValue($value) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 存入一个有实效性的键值队 | 
|      */ | 
|     protected function set_time($key, $value, $expire = 600){ | 
|         return $this->redis->setex($this->formatKey($key), $expire, $this->formatValue($value)); | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 更新具有有效时间key的value,不重置有效时间 | 
|      * @author Axios <axioscros@aliyun.com> | 
|      */ | 
|     protected function save_time($key, $value) | 
|     { | 
|         if($this->get_exists($key)){ | 
|             $ttl  = $this->get_time_ttl($key); | 
|             return $this->set_time($key,$value,$ttl); | 
|         } | 
|   | 
|         return NULL; | 
|     } | 
|   | 
|     /** | 
|      * 统一get/set方法,对于set_Time使用get_Time | 
|      */ | 
|     protected function get_time($key){ | 
|         $value = $this->redis->get($this->formatKey($key)); | 
|         return $value !== FALSE ? $this->unformatValue($value) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 得到一个key的生存时间 | 
|      */ | 
|     protected function get_time_ttl($key){ | 
|         $value = $this->redis->ttl($this->formatKey($key)); | 
|         return $value !== FALSE ? $value : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 批量插入k-v,请求的v需要是一个数组 如下格式 | 
|      * array('key0' => 'value0', 'key1' => 'value1') | 
|      */ | 
|     protected function set_list($value){ | 
|         $data = array(); | 
|         foreach($value as $k => $v){ | 
|             $data[$this->formatKey($k)] = $this->formatValue($v); | 
|         } | 
|         return $this->redis->mset($data); | 
|     } | 
|   | 
|     /** | 
|      * 批量获取k-v,请求的k需要是一个数组 | 
|      */ | 
|     protected function get_list($key){ | 
|         $data = array(); | 
|         foreach($key as $k => $v){ | 
|             $data[] = $this->formatKey($v); | 
|         } | 
|         $rs = $this->redis->mget($data); | 
|         foreach($rs as $k => $v){ | 
|             $rs[$k] = $this->unformatValue($v); | 
|         } | 
|         return $rs; | 
|     } | 
|   | 
|     /** | 
|      * 判断key是否存在。存在 true 不在 false | 
|      */ | 
|     protected function get_exists($key){ | 
|         return $this->redis->exists($this->formatKey($key)); | 
|     } | 
|   | 
|     /** | 
|      * 返回原来key中的值,并将value写入key | 
|      */ | 
|     protected function get_getSet($key, $value){ | 
|         $value = $this->redis->getSet($this->formatKey($key), $this->formatValue($value)); | 
|         return $value !== FALSE ? $this->unformatValue($value) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * string,名称为key的string的值在后面加上value | 
|      */ | 
|     protected function set_append($key, $value){ | 
|         return $this->redis->append($this->formatKey($key), $this->formatValue($value)); | 
|     } | 
|   | 
|     /** | 
|      * 返回原来key中的值,并将value写入key | 
|      */ | 
|     protected function get_strlen($key){ | 
|         return $this->redis->strlen($this->formatKey($key)); | 
|     } | 
|   | 
|     /** | 
|      * 自动增长 | 
|      * value为自增长的值默认1 | 
|      */ | 
|     protected function get_incr($key, $value = 1){ | 
|         return $this->redis->incr($this->formatKey($key), $value); | 
|     } | 
|   | 
|     /** | 
|      * 自动减少 | 
|      * value为自减少的值默认1 | 
|      */ | 
|     protected function get_decr($key, $value = 1){ | 
|         return $this->redis->decr($this->formatKey($key), $value); | 
|     } | 
|     //------------------------------------------------List类型------------------------------------------------- | 
|   | 
|     /** | 
|      * 写入队列左边 并根据名称自动切换库 | 
|      */ | 
|     protected function set_lPush($key, $value){ | 
|         return $this->redis->lPush($this->formatKey($key), $this->formatValue($value)); | 
|     } | 
|   | 
|     /** | 
|      * 写入队列左边 如果value已经存在,则不添加 并根据名称自动切换库 | 
|      */ | 
|     protected function set_lPushx($key, $value){ | 
|         return $this->redis->lPushx($this->formatKey($key), $this->formatValue($value)); | 
|     } | 
|   | 
|     /** | 
|      * 写入队列右边 并根据名称自动切换库 | 
|      */ | 
|     protected function set_rPush($key, $value){ | 
|         return $this->redis->rPush($this->formatKey($key), $this->formatValue($value)); | 
|     } | 
|   | 
|     /** | 
|      * 写入队列右边 如果value已经存在,则不添加 并根据名称自动切换库 | 
|      */ | 
|     protected function set_rPushx($key, $value){ | 
|         return $this->redis->rPushx($this->formatKey($key), $this->formatValue($value)); | 
|     } | 
|   | 
|     /** | 
|      * 读取队列左边 | 
|      */ | 
|     protected function get_lPop($key){ | 
|         $value = $this->redis->lPop($this->formatKey($key)); | 
|         return $value != FALSE ? $this->unformatValue($value) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 读取队列右边 | 
|      */ | 
|     protected function get_rPop($key){ | 
|         $value = $this->redis->rPop($this->formatKey($key)); | 
|         return $value != FALSE ? $this->unformatValue($value) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 读取队列左边 如果没有读取到阻塞一定时间 并根据名称自动切换库 | 
|      */ | 
|     protected function get_blPop($key){ | 
|         $value = $this->redis->blPop($this->formatKey($key), DI()->config->get('app.redis.blocking')); | 
|         return $value != FALSE ? $this->unformatValue($value[1]) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 读取队列右边 如果没有读取到阻塞一定时间 并根据名称自动切换库 | 
|      */ | 
|     protected function get_brPop($key){ | 
|         $value = $this->redis->brPop($this->formatKey($key), DI()->config->get('app.redis.blocking')); | 
|         return $value != FALSE ? $this->unformatValue($value[1]) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 名称为key的list有多少个元素 | 
|      */ | 
|     protected function get_lSize($key){ | 
|         return $this->redis->lSize($this->formatKey($key)); | 
|     } | 
|   | 
|     /** | 
|      * 返回名称为key的list中指定位置的元素 | 
|      */ | 
|     protected function set_lSet($key, $index, $value){ | 
|         return $this->redis->lSet($this->formatKey($key), $index, $this->formatValue($value)); | 
|     } | 
|   | 
|     /** | 
|      * 返回名称为key的list中指定位置的元素 | 
|      */ | 
|     protected function get_lGet($key, $index){ | 
|         $value = $this->redis->lGet($this->formatKey($key), $index); | 
|         return $value != FALSE ? $this->unformatValue($value[1]) : NULL; | 
|     } | 
|   | 
|     /** | 
|      * 返回名称为key的list中start至end之间的元素(end为 -1 ,返回所有) | 
|      */ | 
|     protected function get_lRange($key, $start, $end){ | 
|         $rs = $this->redis->lRange($this->formatKey($key), $start, $end); | 
|         foreach($rs as $k => $v){ | 
|             $rs[$k] = $this->unformatValue($v); | 
|         } | 
|         return $rs; | 
|     } | 
|   | 
|     /** | 
|      * 截取名称为key的list,保留start至end之间的元素 | 
|      */ | 
|     protected function get_lTrim($key, $start, $end){ | 
|         $rs = $this->redis->lTrim($this->formatKey($key), $start, $end); | 
|         foreach($rs as $k => $v){ | 
|             $rs[$k] = $this->unformatValue($v); | 
|         } | 
|         return $rs; | 
|     } | 
|   | 
|     //未实现 lRem lInsert  rpoplpush | 
|   | 
|     //----------------------------------------------------set类型--------------------------------------------------- | 
|     //----------------------------------------------------zset类型--------------------------------------------------- | 
|     //----------------------------------------------------Hash类型--------------------------------------------------- | 
|   | 
|     //----------------------------------------------------通用方法--------------------------------------------------- | 
|     /** | 
|      * 永久计数器,回调当前计数 | 
|      * @author Axios <axioscros@aliyun.com> | 
|      */ | 
|     public function counter_forever($key,$dbname=0){ | 
|         $this->switchDB($dbname); | 
|         if($this->get_exists($key)){ | 
|             $count = $this->get_forever($key); | 
|             $count++; | 
|             $this->set_forever($key,$count); | 
|         }else{ | 
|             $count = 1; | 
|             $this->set_forever($key,$count); | 
|         } | 
|   | 
|         return $count; | 
|     } | 
|     /** | 
|      * 创建具有有效时间的计数器,回调当前计数,单位毫秒ms | 
|      * @author Axios <axioscros@aliyun.com> | 
|      */ | 
|     public function counter_time_create($key,$expire  = 1000,$dbname=0){ | 
|         $this->switchDB($dbname); | 
|         $count = 1; | 
|         $this->set_time($key,$count,$expire); | 
|         $this->redis->pSetEx($this->formatKey($key), $expire, $this->formatValue($count)); | 
|         return $count; | 
|     } | 
|     /** | 
|      * 更新具有有效时间的计数器,回调当前计数 | 
|      * @author Axios <axioscros@aliyun.com> | 
|      */ | 
|     public function counter_time_update($key,$dbname=0){ | 
|         $this->switchDB($dbname); | 
|         if($this->get_exists($key)){ | 
|             $count = $this->get_time($key); | 
|             $count++; | 
|             $expire = $this->redis->pttl($this->formatKey($key)); | 
|             $this->set_time($key,$count,$expire); | 
|             return $count; | 
|         } | 
|         return false; | 
|     } | 
|     /** | 
|      * 设定一个key的活动时间(s) | 
|      */ | 
|     protected function setTimeout($key, $time = 600){ | 
|         return $this->redis->setTimeout($key, $time); | 
|     } | 
|   | 
|     /** | 
|      * 返回key的类型值 | 
|      */ | 
|     protected function type($key){ | 
|         return $this->redis->type($key); | 
|     } | 
|   | 
|     /** | 
|      * key存活到一个unix时间戳时间 | 
|      */ | 
|     protected function expireAt($key, $time = 600){ | 
|         return $this->redis->expireAt($key, $time); | 
|     } | 
|   | 
|     /** | 
|      * 随机返回key空间的一个key | 
|      */ | 
|     public function randomKey(){ | 
|         return $this->redis->randomKey(); | 
|     } | 
|   | 
|     /** | 
|      * 返回满足给定pattern的所有key | 
|      */ | 
|     protected function keys($key, $pattern){ | 
|         return $this->redis->keys($key, $pattern); | 
|     } | 
|   | 
|     /** | 
|      * 查看现在数据库有多少key | 
|      */ | 
|     protected function dbSize(){ | 
|         return $this->redis->dbSize(); | 
|     } | 
|   | 
|     /** | 
|      * 转移一个key到另外一个数据库 | 
|      */ | 
|     protected function move($key, $db){ | 
|         $arr = DI()->config->get('app.redis.DB'); | 
|         $rs  = isset($arr[$db]) ? $arr[$db] : $db; | 
|         return $this->redis->move($key, $rs); | 
|     } | 
|   | 
|     /** | 
|      * 给key重命名 | 
|      */ | 
|     protected function rename($key, $key2){ | 
|   | 
|         return $this->redis->rename($key, $key2); | 
|     } | 
|   | 
|     /** | 
|      * 给key重命名 如果重新命名的名字已经存在,不会替换成功 | 
|      */ | 
|     protected function renameNx($key, $key2){ | 
|         return $this->redis->renameNx($key, $key2); | 
|     } | 
|   | 
|     /** | 
|      * 删除键值 并根据名称自动切换库(对所有通用) | 
|      */ | 
|     protected function del($key){ | 
|         return $this->redis->del($this->formatKey($key)); | 
|     } | 
|   | 
|     /** | 
|      * 返回redis的版本信息等详情 | 
|      */ | 
|     public function info(){ | 
|         return $this->redis->info(); | 
|     } | 
|   | 
|     /** | 
|      * 切换DB并且获得操作实例 | 
|      */ | 
|     public function get_redis(){ | 
|         return $this->redis; | 
|     } | 
|   | 
|     /** | 
|      * 查看连接状态 | 
|      */ | 
|     public function ping(){ | 
|         return $this->redis->ping(); | 
|     } | 
|   | 
|     /** | 
|      * 内部切换Redis-DB 如果已经在某个DB上则不再切换 | 
|      */ | 
|     protected function switchDB($name){ | 
|         $arr = DI()->config->get('app.redis.DB'); | 
|         if(is_int($name)){ | 
|             $db = $name; | 
|         }else{ | 
|             $db = isset($arr[$name]) ? $arr[$name] : 0; | 
|         } | 
|         if($this->db_old != $db){ | 
|             $this->redis->select($db); | 
|             $this->db_old = $db; | 
|         } | 
|     } | 
|     //-------------------------------------------------------谨慎使用------------------------------------------------ | 
|   | 
|     /** | 
|      * 清空当前数据库 | 
|      */ | 
|     protected function flushDB(){ | 
|         return $this->redis->flushDB(); | 
|     } | 
|   | 
|     /** | 
|      * 清空所有数据库 | 
|      */ | 
|     public function flushAll(){ | 
|         return $this->redis->flushAll(); | 
|     } | 
|   | 
|     /** | 
|      * 选择从服务器 | 
|      */ | 
|     public function slaveof($host, $port){ | 
|         return $this->redis->slaveof($host, $port); | 
|     } | 
|   | 
|     /** | 
|      * 将数据同步保存到磁盘 | 
|      */ | 
|     public function save(){ | 
|         return $this->redis->save(); | 
|     } | 
|   | 
|     /** | 
|      * 将数据异步保存到磁盘 | 
|      */ | 
|     public function bgsave(){ | 
|         return $this->redis->bgsave(); | 
|     } | 
|   | 
|     /** | 
|      * 返回上次成功将数据保存到磁盘的Unix时戳 | 
|      */ | 
|     public function lastSave(){ | 
|         return $this->redis->lastSave(); | 
|     } | 
|   | 
|     /** | 
|      * 使用aof来进行数据库持久化 | 
|      */ | 
|     protected function bgrewriteaof(){ | 
|         return $this->redis->bgrewriteaof(); | 
|     } | 
| } |