用闭包实现非侵入式缓存

来源:互联网 发布:网络促销手段 编辑:程序博客网 时间:2024/05/19 18:37

目标 :PHP 用闭包实现非侵入式缓存
优点 :
- 非侵入式
- 依赖注入

写这个博客的原因是:
公司项目大量的使用了缓存,但是我们最开始使用的缓存代码耦合度太高,并且代码看起来比较混乱。所以我决定写一个非侵入式的缓存系统,将正常代码和缓存代码分开,降低耦合度。 但是传统的纯面向对象的实现会出现大量的类。而PHP借助于闭包特性可以用较少的类实现,并且避免了继承这种强耦合。

实现:
常见缓存代码:

        $live = $redis->get('home_live_'.$page);        if(!$live){            $live = $member->live($page);            $redis->set('home_live_'.$page,serialize($live),10);        }        else{            $live = unserialize($live);        }

这种方式的缺点是:缓存代码与原代码耦合太严重,一旦决定不使用缓存或者更换缓存会非常麻烦

非侵入式缓存:
1.纯面向对象实现方式:

class Cache{}interface MemberModelInterface{    public function getList();}class MemberModel implements MemberModelInterface{    public function getList()    {        return array('1','2','3','4','5');    }}class BaseModelCache{    const CACHE_OPEN  = false;    private $redis;    private $model;    public function __construct(UserModel $model)    {        $this->redis = new \Redis;        $this->redis->connect('127.0.0.1',6379);        $this->model = $model;    }    public function cache($method , $params , $expire)    {        $rs = $this->redis->get('list');        if(!$rs || self::CACHE_OPEN !== true){            $rss = call_user_func_array([$this->model,$method],$params);            $this->redis->set('list',json_encode($rss),$expire);        }        return $rs;    }}class MemberModelCache extends BaseModelCache implements MemberModelInterface{    public function __construct(MemberModel $model)    {        parent::__construct($model);    }    public function getList()    {        // TODO: Implement getList() method.        return $this->cache('getList',[],100);    }}$member = new MemberModelCache(new MemberModel());var_dump($member->getList());

这里没有把缓存类封装起来,所以Cache类是空的。这种实现方法每个Model都需要有一个cache类并且实现同一个接口。类数量太多的同时,由于Model类和ModelCache类需要同时实现一个接口,所以也具有较高的耦合度。

闭包实现:

<?phpclass RedisCache{    private $handler;    public function __construct($options=array()) {        $options = array_merge(array (            'host'          =>  '127.0.0.1',            'port'          =>  6379,            'timeout'       =>  false,            'persistent'    =>  false,        ),$options);        $this->handler  = new \Redis;        $this->handler->connect($options['host'], $options['port']) :    }    public function cache(Closure $func,$expire,$cacheName)    {        $rs = $this->handler->get($cacheName);        if(!$rs){            $rs = $func();            $this->handler->set($cacheName,json_encode($rs),$expire);        }        return $rs;    }    public function __call($func_name,$args)    {        return call_user_func_array([$this->handler,$func_name],$args);    }}class NonInvasiveCache{    const DEFAULT_CACHE_TYPE = 'Redis';    private $cache;    public function __construct()    {        $this->cache = $this->connect('Redis');    }    public function connect($cacheType='',$options=array())    {        if(empty($cacheType)) $cacheType = self::DEFAULT_CACHE_TYPE;        $class = $cacheType.'Cache';        if(class_exists($class)){            $cache = new $class($options);        }        else{             throw new Exception($cacheType.' Driver does not exists');        }        return $cache;    }    public  function useCache($func,$expire,$cacheName){        if(is_array($func)){            if(is_object($func[0]) && is_string($func[1]) && (empty($func[2]) || is_array($func[2]) )){                $func = $this->makeClosure($func[0],$func[1],$funcp[2]);            }else{                throw new Exception('First param error');            }        }        $funcRf = new \ReflectionFunction($func);        if(!$funcRf->isClosure()){            throw new Exception('First param error,it must be a Closure or Array');        }        return $this->cache->cache($func,$expire,$cacheName);    }    public  function makeClosure(&$class,$mothod,$args=array()){        $f = function() use(&$class,&$mothod,&$args){//               xdebug_debug_zval( 'class' );//查看引用计数,没有拷贝对象的操作                 return call_user_func_array([$class,$mothod],$args);             };        return $f;    }    public static  function instance()    {        static $thisCache = false;        if(!$thisCache){            $thisCache = new NonInvasiveCache();        }        return $thisCache;    }}class MemberModel {    public function getList()    {        return array('1','2','3','4','5');    }}$member  = new MemberModel();$cache   = new NonInvasiveCache();//两种用法://第一种:第一个参数传数组,第二个参数传过期时间,第三个参数是键名$data  = $cache->useCache([$user,'getList'],10,'redisCache');//第二种:第一个参数传匿名函数$data  = $cache->useCache(function(){return array('1','2','3','4','5');},10,'redisCache');

使用闭包实现减少了类的数量,并且Model类不需要实现接口,降低了耦合度,还可以使用匿名函数,使用起来更加方便。
这里只封装了使用普通的字符类型做缓存的例子,简单介绍一下这个实现方法。

0 0
原创粉丝点击