• 技术文章 >php教程 >php手册

    浅谈对CACHE操作的封装及最佳实践

    2016-06-06 20:14:09原创642

    作为WEB开发者,CACHE对我们来说是再熟悉不过了。但是,你真的有研究如何把它用得更“优雅”吗?下面以较常见的Memcache为例,谈谈对CACHE操作的几种常见封装方法,并推荐一种我认为最佳的实践。如果你有更好的解决方案,请不吝赐教:) 为什么要封装? ?php

    作为WEB开发者,CACHE对我们来说是再熟悉不过了。但是,你真的有研究如何把它用得更“优雅”吗?下面以较常见的Memcache为例,谈谈对CACHE操作的几种常见封装方法,并推荐一种我认为最佳的实践。如果你有更好的解决方案,请不吝赐教:)

    为什么要封装?

    addServers('127.0.0.1', 11211);
    $key = 'test';
    $duration = 3600;
    $value = $mc->get($key);
    if ($mc->getResultCode() == Memcached::RES_NOTFOUND) {
        $value = getValueFromDB();
        $mc->set($key, $value, $duration);
    }

    第一次使用CACHE的同学,往往会写出上面的代码。简陋且有效,拿来写个Hello World是再合适不过了,但是真正在项目中使用CACHE的时候,还这么写就太low了。没有异常处理和重试机制、不能做负载均衡,大量的重复代码……当你受不了维护之繁琐时,就会想办法来解决这些问题,那就是封装。

    封装的好处很明显:
    1、减少代码量,提升可读性和可复用性;
    2、可以在封装层内部增加负载均衡、数据压缩、键值HASH、异常处理、重试机制等等各种功能,提升可维护性和鲁棒性。

    那么问题来了,该怎么封装呢?

    实例句柄封装

    _MC = new Memcached();
    ? ? ? ? $this->_MC->addServers(self::MC_IP, self::MC_PORT);
    ? ? }
    ? ? public function get($key) {
    ? ? ? ? return $this->_MC->get($key);
    ? ? }
    ? ? public function set($key, $value, $duration) {
    ? ? ? ? return $this->_MC->set($key, $value, $duration);
    ? ? }
    ? ? public function missed() {
    ? ? ? ? return $this->_MC->getResultCode() == Memcached::RES_NOTFOUND;
    ? ? }
    }
    // 调用代码
    $key = 'test';
    $duration = 3600;
    $mcHandle = new MemCacheHandle();
    $value = $mcHandle->get($key);?
    if ($mcHandle->missed()) {
        $value = getValueFromDB();
        $mcHandle->set($key, $value, $duration);
    }

    你可能会说了,这看上去和不封装区别不大,只是少了一句addServers嘛。但是让我们看看有了这么一层封装,能做些什么事情:

    1、将服务器配置信息和业务代码隔离,并可以在构造方法中做负载均衡;
    2、可以在get方法中对键值进行唯一性HASH,统一键值长度,避免超长的KEY;
    3、可以在set方法中对存入的数据进行压缩,减少服务器的资源占用;
    4、可以在get和set方法中做异常处理,记录LOG,或加上重试机制;
    5、将Memcache的相关细节隐藏了起来,你可以换成redis之类,对用户是完全透明的。

    虽然成果喜人,但是还是有点问题:在每个使用CACHE的地方都要实例化一个MemCacheHandle,多次使用就要多次实例化。虽然你可以在业务代码中对实例做持有,但是跨业务线和跨代码库的多次使用呢?

    静态方法封装

    get($key);
        }
        public static function set($key, $value, $duration) {
            return self::_getInstance()->set($key, $value, $duration);
        }
        public static function missed() {
            return self::_getInstance()->missed();
        }
        private static function _getInstance() {
            if (!isset(self::$_INSTANCE)) {
                self::$_INSTANCE = new MemCacheHandle();
            }
            return self::$_INSTANCE;
        }
    }
    // 调用代码
    $key = 'test';
    $duration = 3600;?
    $value = MCache::get($key);
    if (MCache::missed()) {
        $value = getValueFromDB();
        MCache::set($key, $value, $duration);
    }?

    你可能会问了:这一点也不面向对象嘛,用静态方法封装有什么好处呢?

    1、隐藏了实例化的过程,少了一句代码,少使用一个变量,这是看得见的实惠;
    2、内部使用单例模式(后续还可改成连接池),避免了重复的实例化,让业务端调用无后顾之忧,这点很重要

    似乎到这里调用端的代码就已经简化到头了,读取、判断、写入这三句是肯定少不了的。但真的是这样吗?

    最佳实践:静态方法+闭包封装

    
    

    如果你从没用过PHP的闭包(5.3版本才开始提供),看到这里我想你已经说不出话来了。

    调用端只知道要在从DB取值前要过一层Cache,指定一下使用的键值和生命周期就好了。那么为什么要关心具体的逻辑呢?什么key、duration这样的变量都可以不用,就连最基本的读取、判断、写入这三句,我们也封装起来了。

    没有一个临时变量,一句代码就搞定,这就是最完美的封装

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:php-fpm平滑启动并配置服务 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • 用Xdebug修正PHP应用程序中的错误• PHP下打开phpMyAdmin出现403错误的问题解决方法• php实现refresh刷新页面批量导入数据的方法• PHP array_multisort()函数的使用札记• php用header()实现文件下载,下载的文件提示被破坏不能打开的解决办法
    1/1

    PHP中文网