用户
 找回密码
 入住 CI 中国社区
搜索
查看: 15509|回复: 9
收起左侧

[高级] CI框架修复Memcached的使用案例

[复制链接]
发表于 2013-7-3 11:45:47 | 显示全部楼层 |阅读模式
本帖最后由 gogogo1027 于 2014-9-11 10:21 编辑

2014-09-11更新:
太多人咨询过这个问题,我已经整理过一次了,而且扩展过CI config的核心,只是扩展,并不影响原来的功能,现在把完整的代码贴出来,直接下载附件就可以了。原则上可以直接替换,如不放心可以对比一下现有代码再替换。我的cache方法是写在common_helper.php上,而且在初始化(autoload)里面自动调用了这个公共函数。如果你已经有了其他公共辅助函数,你可以把common_helper.php里面的方法直接复制到你对应的公共函数库中。

我自己用的Cache有4种,分别是Memcache,file,Dbcahc,SSDB,当然这里贴出只有memcache
补充一下,为了方便控制,需要在application/config/config.php上添加一个配置项:memcache_enable = true;
QQ图片20140911101613.jpg

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



前段时间研究了一下CI的Cache功能,发觉其他功能还好,比如可以以文件形式缓存,也可以以Memcached形式缓存。
后来仔细看了一下CI的Memcache核心处理文件,发觉他的代码都有bug,根本是不能使用,现在在原来的基础上修改了一份,并且扩展了辅助函数,应该非常好用。
也许有人会说可以直接单独扩展一个Memcached 的library,但是我觉得完全没必要,因为CI的思想已经够好了,而且能自定义选择是以Memcache缓存还是以file的形式缓存(考虑到有些服务器上未装载Memcache,系统会自动以文本形式缓存)下面说说详细的步骤:
第一步:
CI的Memcached核心文件在system\libraries\Cache\drivers\Cache_memcached.php下
默认的配置
PHP复制代码
 
protected $_memcache_conf  = array(
     'default' => array(
      'default_host'  => '127.0.0.1',
      'default_port'  => 11211,
      'default_weight' => 1
     )
    );
 
复制代码

再看看下面是如何进行的:
PHP复制代码
 
//CI的初始化和连接Memcached方法
$this->_memcached = new Memcached();
$this->_memcached->addServer(
     $cache_server['hostname'], $cache_server['port'], $cache_server['weight']
   );
//这个可能跟Memcached版本有关,我的版本是会报错的,我安装的Memcache是这样初始化的
$this->_memcached = new Memcache();
$this->_memcached = connect($cache_server['hostname'], $cache_server['port'], );
//所以如果要兼容两者,则改成
if(extension_loaded('memcache')){
   $this->_memcached = new Memcache();
  }else if(extension_loaded('memcached')){
   $this->_memcached = new Memcached();
  }
//连接方式则改成
 
if(extension_loaded('memcached')){
    $this->_memcached->addServer(
     $cache_server['hostname'], $cache_server['port'], $cache_server['weight']
    );
   }elseif(extension_loaded('memcache')){
    $this->_memcached->connect($cache_server['hostname'],$cache_server['port']);
   }
 
注意这个函数,这个是判断是否存在Memcached,存在则调用相当于__construct()
/**
  * Is supported
  *
  * Returns FALSE if memcached is not supported on the system.
  * If it is, we setup the memcached object & return TRUE
  */

public function is_supported()
{
  if ( ! extension_loaded('memcached') AND !extension_loaded('memcache'))//这里的AND !extension_loaded('memcache'))是旧版本的CI判断
  {
   log_message('error', 'The Memcached Extension must be loaded to use Memcached Cache.');
   
   return FALSE;
  }
 
  $this->_setup_memcached();//调用初始化
  return TRUE;
}
 
//初始化函数是先判断config下有没有Memcached.php的配置文件,如果有则调用并替换掉默认的$_memcache_conf的设置,见代码:
if ($CI->config->load('memcached', TRUE, TRUE))
  {
   if (is_array($CI->config->config['memcached']))
   {
    $this->_memcache_conf = NULL;
    foreach ($CI->config->config['memcached'] as $name => $conf)
    {
     $this->_memcache_conf[$name] = $conf;
    }    
   }
   
  }
 
 
复制代码

这样基本上能满足Memcached的功能扩展。
修改的文件参见附件Cache_memcached.rar



第二步:
1,在application的helpers下写一个辅助公共函数common_helper.php,并在autoload里调用,以后的公共函数都往里面写。注意,系统已经有了一个Common.php核心公共辅助函数,但common_helper.php跟它一点关系都没有,只是命名则这样而已,并非是它的扩展。(核心Common.php根据CI的扩展方法是无法扩展的,因为Common.php是系统最开始简单的load调入的,那个时候还没有像后面那样的其他辅助函数的扩展功能,详情不细说,自己看源代码去)。
2,写一个cache()方法,代码如下:
PHP复制代码
 
/**
* 数据缓存
*
* 该函数可选择以Memcache缓存还是以文件写入形式缓存。
* 这里需要在config/config.php下增加一个配置$config['memcached']['enable']='TRUE',用来开启或关闭Memcache,状态为关闭的话,则自动切换成文件缓存
* 如果开启Memcache,在config.php下修改$config['memcached']['enable']=TRUE;
* 否则缓存信息将以文本形式存储在application/cache文件夹下。
* 文件命名格式:$key+md5(ip_address+user_aguent);
* 如果能用Memcache就尽量用,不要使用文本,否则会产生一堆的垃圾文件
* 已写垃圾回收机制
* 注意,该函数缓存的数据只针对某个用户而非类似缓存新闻列表等全局调用的。
* 如需使用全局的缓存,则使用memory()方法替代
*
* @param string $cmd get|set|rm
* @param string $key
* @param mixed $value
* @param int $expire
* @return mixed
*
*/

function cache($cmd,$key,$value=null,$expire=600) {
static $ways = null;
$CI =& get_instance();
if(is_null($ways)){
  $mem = $CI->config->item('memcache');
  if($mem['enable'] === TRUE){
   $ways = 'memcached';
  }else{
   $ways = 'file';
  }
}
 
$CI->load->driver('cache');
$subfix = '';
$subfix .= trim(substr($CI->input->user_agent(), 0, 120));
$subfix .= $CI->input->ip_address();
$key .= '_'.md5($subfix);
switch ($cmd) {
  case 'get':
   return $CI->cache->$ways->get($key);
   break;
  case 'set':
   return $CI->cache->$ways->save($key,$value,$expire);
   break;
  case 'rm':
   $CI->cache->$ways->delete($key);
   break;
}
}
 
复制代码


值得注意的是,该函数存储的缓存是以用户为单位的非全局的,也就是说,某个用户存储的东西只有这个用户才能调用,而不像传统的那种,定义了一个新闻列表缓存,全部用户都能使用。

如果想全局的Memcache,我也扩展了一个函数
代码:
PHP复制代码
 
/**
* 内存操作
* 此函数为使用全局memcache的便携操作
*
* $cmd = get|set|rm
*
* @param mix $cmd
* @param string $key
* @param mix $value
* @param int $expire
*/

function memory($cmd, $key, $value=null, $expire=600) {
static $enable = null;
$CI =& get_instance();
if (is_null($enable)) {
  $mem_config = $CI->config->item('memcache');
  $enable = $mem_config['enable'];
}
if ($enable) {
  $CI->load->driver('cache');
  switch ($cmd) {
   case 'get': return $CI->cache->memcached->get($key); break;
   case 'set': return $CI->cache->memcached->save($key, $value,$expire); break;
   case 'rm' : return $CI->cache->memcached->delete($key); break;
  }
}else {
  show_error('Can not connect to memory server', 500);//在config.php下配置中打开memcahce
}
}
 
复制代码


全局的文件缓存
PHP复制代码
 
/**
* 文本方式缓存
*
* 使用文本缓存,效果跟memory一样
*
* @param string $cacheName
* @return mixed
*/

function file_cache($cmd, $key, $value=null, $expire=600) {
static $writeable = null;
$cache_path = APPPATH.'/cache';
 
if(is_null($writeable)){
  $writeable = is_really_writable($cache_path);
}
if($writeable == TRUE){
  $CI =& get_instance();
  $CI->load->driver('cache');
  switch ($cmd) {
   case 'get': return $CI->cache->file->get($key); break;
   case 'set': return $CI->cache->file->save($key, $value,$expire); break;
   case 'rm' : return $CI->cache->file->delete($key); break;
  }
}else{
  show_error("Directory:$cache_path is unwritable",500);
}
}
 
复制代码



common_helper.php的源文件见附件:



如有疑问,可以加q:349703434共同探讨



php.rar

16.81 KB, 下载次数: 303

发表于 2013-7-3 17:37:29 | 显示全部楼层
common_helper.php有什么好处?
为什么不用$this->cacahe直接操作?
 楼主| 发表于 2013-7-3 20:37:05 | 显示全部楼层
kinwyb 发表于 2013-7-3 17:37
common_helper.php有什么好处?
为什么不用$this->cacahe直接操作?

也可以的,只是每次cache的时候你还要传递参数,还要load一次driver
common_helper.php里面的函数已经帮你做了这些。
发表于 2013-12-2 15:30:58 | 显示全部楼层
发表于 2014-1-16 14:04:26 | 显示全部楼层
实在是太棒了。
发表于 2014-4-10 10:31:44 | 显示全部楼层
附件去哪里了?我怎么看不到附件。
发表于 2014-8-15 15:36:35 | 显示全部楼层
楼主大哥,附件在哪?
发表于 2014-8-25 10:33:02 | 显示全部楼层
怎么没看见附件~~~~~·

本版积分规则