Redis、Memcached简单封装

本文介绍了一种简单的PHP缓存控制类封装方法,旨在避免重复的缓存判断逻辑。通过定义接口,实现了Redis和Memcached之间的无缝切换。当缓存中无数据时,使用者可以提供回调函数,该函数将在找不到数据时执行,并将返回结果自动存储回缓存,增加了代码的灵活性和适用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        很多项目中都会用到memcached、redis作缓存,一般我们获取数据都会优先从缓存获取数据,如果缓存中没有,再去读取数据库或者从其他方式获得相应的数据,处理之后返回同时种入缓存,那么很多时候代码便要重复这样一个判断逻辑,于是在这里,考虑了这么一种方式,简单地封装了一个缓存控制类,在从缓存读取数据的时候传入一个回调函数,如果缓存中不存在就执行回调函数,返回回调函数的结果,并自动将结果存入缓存。

        首先定义缓存控制类的接口

    interface Interface_Cache {
        
        /**
         * 获取当前缓存控制类实例,单例模式
         */
        public static function getInstance();
        
        /**
         * 获取当前类中原生mc、redis对象
         */
        public function query();
        
        /**
         * 读取配置设置缓存
         * @param array $cache_config 缓存配置
         * @param array $cache_params 缓存参数,构造key
         * @param callable $func 回调函数,返回应当设置的值,返回值为null时,不设置缓存数据
         */
        public function set(array $cache_config, array $cache_params, callable $func);
        
        /**
         * 优先从缓存读取数据,如果缓存中不存在,执行回调函数获得数据返回,同时将数据写入缓存
         * @param array $cache_config 缓存配置
         * @param array $cache_params 缓存参数,构造key
         * @param callable $func 回调函数,返回查询的数据,返回值为null时,不写入缓存
         */
        public function get(array $cache_config, array $cache_params, callable $func);
        
    }

  然后进行不同的实现

  memcached


    class Base_Mc implements Interface_Cache {
        private $_mc = null;
        private static $_instance = null;
        
        private function __construct() {
            $this->_mc = new Memcached();
            $this->_mc->addServer('127.0.0.1', 11211);
        }
        
        public static function getInstance() {
            if(is_null(self::$_instance)) {
                self::$_instance = new self();
            }
            return self::$_instance;
        }
       
        public function query() {
            return $this->_mc;
        }
        
        public function set(array $cache_config, array $cache_params, callable $func) {
            $key = self::buildKey($cache_params, $cache_config['key']);
            $expire = $cache_config['expire'];
            
            $data = call_user_func($func);
            if(is_null($data)) {
                return false;
            }
            $expire += $expire == 0? 0: time();
            return $this->_mc->set($key, $data, $expire);
        }
        
        public function get(array $cache_config, array $cache_params, callable $func) {
            $key = self::buildKey($cache_params, $cache_config['key']);
            $expire = $cache_config['expire'];
            
            $data = null;
            if(false === ($data = $this->_mc->get($key))) {
                $data = call_user_func($func);
                if(is_null($data)) {
                    return null;
                }
                $expire += $expire == 0? 0: time();
                $this->_mc->set($key, $data, $expire);
            }
            return $data;
        }
        
        private static function buildKey(array $args, $format) {
            $key = vsprintf($format, $args);
            return $key;
        }
        
        public function __destruct() {
            unset($this->_mc);
        }
    }

redis,这里采用字符串或哈希的结构设置缓存


    class Base_Redis implements Interface_Cache {
        private $_redis = null;
        private static $_instance = null;
        
        private function __construct() {
            if(is_null($this->_redis)) {
                $this->_redis = new Redis();
                $this->_redis->connect('127.0.0.1', '6379', 3);
            }
        }
        
        public static function getInstance() {
            if(is_null(self::$_instance)) {
                self::$_instance = new self();
            }
            return self::$_instance;
        }
        
        public function query() {
            return $this->_redis;
        }
        
        public function set(array $cache_config, array $cache_params, callable $func) {
            $key = self::buildKey($cache_params, $cache_config['key']);
            $expire = $cache_config['expire'];
            
            $type = null;
            $data = call_user_func($func);
            if(is_null($data)) {
                return false;
            }
            
            if(is_string($data) || is_numeric($data)) {
                $this->_redis->setex($key, $expire, $data);
            } else if(is_array($data)) {
                $this->_redis->hMset($key, $data);
                $this->_redis->expire($key, $expire);
            }
            return true;
        }
        
        
        public function get(array $cache_config, array $cache_params, callable $func) {
            $key = self::buildKey($cache_params, $cache_config['key']);
            $expire = $cache_config['expire'];
            
            $data = null;
            $type = $this->_redis->type($key);
            $data = $type == Redis::REDIS_HASH? $this->_redis->hGetAll($key): $this->_redis->get($key);
            if(false === $data || empty($data)) {
                $data = call_user_func($func);
                
                if(is_null($data)) {
                    return null;
                }
                
                if(is_string($data) || is_numeric($data)) {
                    $this->_redis->setex($key, $expire, $data);
                } else if(is_array($data)) {
                    $this->_redis->hMset($key, $data);
                    $this->_redis->expire($key, $expire);
                }
            }
            return $data;
        }
        
        private static function buildKey(array $args, $format) {
            $key = vsprintf($format, $args);
            $key = str_replace('_', ':', $key);
            return $key;
        }
           
        
        public function __destruct() {
            $this->_redis->close();
            unset($this->_redis);
        } 
    
    }

示例代码


    class UserModel {
        
        public static function getUserInfoById($user_id) {
            $params = ['userId' => $user_id ];
            $mc = Base_Mc::getInstance();
            $cache_config = Comm_Config::get('cache.user');
            $info = $mc->get($cache_config, $params, function() use ($params){
                $user_sql = Impl_User::getInstance();
                $rs = $user_sql->auto()->buildQuery($params)->exec();
                if(empty($rs[0])) {
                    return null;
                }
                return $rs[0][0];
            });
            return $info;
        }
    }

这样实现有一个好处就是能比较容易实现redis、memcached之间的自由切换,考虑用传入回调函数而不是sql语句的方式,一个是因为数据不一定来自数据库,或许来自其他公共的接口等,不是sql而是fsockopen、curl等等,这样能够保证更好的灵活性,其二是通过传sql返回的结果是没有经过相应处理的,适用的范围也相对受限制。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值