PHP 缓存实现代码及详细注释


Posted in PHP onMay 16, 2010
class CacheException extends Exception {} 
/** 
* 缓存抽象类 
*/ 
abstract class Cache_Abstract { 
/** 
* 读缓存变量 
* 
* @param string $key 缓存下标 
* @return mixed 
*/ 
abstract public function fetch($key); /** 
* 缓存变量 
* 
* @param string $key 缓存变量下标 
* @param string $value 缓存变量的值 
* @return bool 
*/ 
abstract public function store($key, $value); 
/** 
* 删除缓存变量 
* 
* @param string $key 缓存下标 
* @return Cache_Abstract 
*/ 
abstract public function delete($key); 
/** 
* 清(删)除所有缓存 
* 
* @return Cache_Abstract 
*/ 
abstract public function clear(); 
/** 
* 锁定缓存变量 
* 
* @param string $key 缓存下标 
* @return Cache_Abstract 
*/ 
abstract public function lock($key); 
/** 
* 缓存变量解锁 
* 
* @param string $key 缓存下标 
* @return Cache_Abstract 
*/ 
abstract public function unlock($key); 
/** 
* 取得缓存变量是否被锁定 
* 
* @param string $key 缓存下标 
* @return bool 
*/ 
abstract public function isLocked($key); 
/** 
* 确保不是锁定状态 
* 最多做$tries次睡眠等待解锁,超时则跳过并解锁 
* 
* @param string $key 缓存下标 
*/ 
public function checkLock($key) { 
if (!$this->isLocked($key)) { 
return $this; 
} 
$tries = 10; 
$count = 0; 
do { 
usleep(200); 
$count ++; 
} while ($count <= $tries && $this->isLocked($key)); // 最多做十次睡眠等待解锁,超时则跳过并解锁 
$this->isLocked($key) && $this->unlock($key); 
return $this; 
} 
} 
/** 
* APC扩展缓存实现 
* 
* 
* @category Mjie 
* @package Cache 
* @author 流水孟春 
* @copyright Copyright (c) 2008- <cmpan(at)qq.com> 
* @license New BSD License 
* @version $Id: Cache/Apc.php 版本号 2010-04-18 23:02 cmpan $ 
*/ 
class Cache_Apc extends Cache_Abstract { 
protected $_prefix = 'cache.mjie.net'; 
public function __construct() { 
if (!function_exists('apc_cache_info')) { 
throw new CacheException('apc extension didn\'t installed'); 
} 
} 
/** 
* 保存缓存变量 
* 
* @param string $key 
* @param mixed $value 
* @return bool 
*/ 
public function store($key, $value) { 
return apc_store($this->_storageKey($key), $value); 
} 
/** 
* 读取缓存 
* 
* @param string $key 
* @return mixed 
*/ 
public function fetch($key) { 
return apc_fetch($this->_storageKey($key)); 
} 
/** 
* 清除缓存 
* 
* @return Cache_Apc 
*/ 
public function clear() { 
apc_clear_cache(); 
return $this; 
} 
/** 
* 删除缓存单元 
* 
* @return Cache_Apc 
*/ 
public function delete($key) { 
apc_delete($this->_storageKey($key)); 
return $this; 
} 
/** 
* 缓存单元是否被锁定 
* 
* @param string $key 
* @return bool 
*/ 
public function isLocked($key) { 
if ((apc_fetch($this->_storageKey($key) . '.lock')) === false) { 
return false; 
} 
return true; 
} 
/** 
* 锁定缓存单元 
* 
* @param string $key 
* @return Cache_Apc 
*/ 
public function lock($key) { 
apc_store($this->_storageKey($key) . '.lock', '', 5); 
return $this; 
} 
/** 
* 缓存单元解锁 
* 
* @param string $key 
* @return Cache_Apc 
*/ 
public function unlock($key) { 
apc_delete($this->_storageKey($key) . '.lock'); 
return $this; 
} 
/** 
* 完整缓存名 
* 
* @param string $key 
* @return string 
*/ 
private function _storageKey($key) { 
return $this->_prefix . '_' . $key; 
} 
} 
/** 
* 文件缓存实现 
* 
* 
* @category Mjie 
* @package Cache 
* @author 流水孟春 
* @copyright Copyright (c) 2008- <cmpan(at)qq.com> 
* @license New BSD License 
* @version $Id: Cache/File.php 版本号 2010-04-18 16:46 cmpan $ 
*/ 
class Cache_File extends Cache_Abstract { 
protected $_cachesDir = 'cache'; 
public function __construct() { 
if (defined('DATA_DIR')) { 
$this->_setCacheDir(DATA_DIR . '/cache'); 
} 
} 
/** 
* 获取缓存文件 
* 
* @param string $key 
* @return string 
*/ 
protected function _getCacheFile($key) { 
return $this->_cachesDir . '/' . substr($key, 0, 2) . '/' . $key . '.php'; 
} 
/** 
* 读取缓存变量 
* 为防止信息泄露,缓存文件格式为php文件,并以"<?php exit;?>"开头 
* 
* @param string $key 缓存下标 
* @return mixed 
*/ 
public function fetch($key) { 
$cacheFile = self::_getCacheFile($key); 
if (file_exists($cacheFile) && is_readable($cacheFile)) { 
return unserialize(@file_get_contents($cacheFile, false, NULL, 13)); 
} 
return false; 
} 
/** 
* 缓存变量 
* 为防止信息泄露,缓存文件格式为php文件,并以"<?php exit;?>"开头 
* 
* @param string $key 缓存变量下标 
* @param string $value 缓存变量的值 
* @return bool 
*/ 
public function store($key, $value) { 
$cacheFile = self::_getCacheFile($key); 
$cacheDir = dirname($cacheFile); 
if(!is_dir($cacheDir)) { 
if(mkdir($cacheDir" target="_blank">!@mkdir($cacheDir, 0755, true)) { 
throw new CacheException("Could not make cache directory"); 
} 
} 
return @file_put_contents($cacheFile, '<?php exit;?>' . serialize($value)); 
} 
/** 
* 删除缓存变量 
* 
* @param string $key 缓存下标 
* @return Cache_File 
*/ 
public function delete($key) { 
if(emptyempty($key)) { 
throw new CacheException("Missing argument 1 for Cache_File::delete()"); 
} 
$cacheFile = self::_getCacheFile($key); 
if($cacheFile" target="_blank">!@unlink($cacheFile)) { 
throw new CacheException("Cache file could not be deleted"); 
} 
return $this; 
} 
/** 
* 缓存单元是否已经锁定 
* 
* @param string $key 
* @return bool 
*/ 
public function isLocked($key) { 
$cacheFile = self::_getCacheFile($key); 
clearstatcache(); 
return file_exists($cacheFile . '.lock'); 
} 
/** 
* 锁定 
* 
* @param string $key 
* @return Cache_File 
*/ 
public function lock($key) { 
$cacheFile = self::_getCacheFile($key); 
$cacheDir = dirname($cacheFile); 
if(!is_dir($cacheDir)) { 
if(mkdir($cacheDir" target="_blank">!@mkdir($cacheDir, 0755, true)) { 
if(!is_dir($cacheDir)) { 
throw new CacheException("Could not make cache directory"); 
} 
} 
} 
// 设定缓存锁文件的访问和修改时间 
@touch($cacheFile . '.lock'); 
return $this; 
} 
/** 
* 解锁 
* 
* @param string $key 
* @return Cache_File 
*/ 
public function unlock($key) { 
$cacheFile = self::_getCacheFile($key); 
@unlink($cacheFile . '.lock'); 
return $this; 
} 
/** 
* 设置文件缓存目录 
* @param string $dir 
* @return Cache_File 
*/ 
protected function _setCacheDir($dir) { 
$this->_cachesDir = rtrim(str_replace('\\', '/', trim($dir)), '/'); 
clearstatcache(); 
if(!is_dir($this->_cachesDir)) { 
mkdir($this->_cachesDir, 0755, true); 
} 
// 
return $this; 
} 
/** 
* 清空所有缓存 
* 
* @return Cache_File 
*/ 
public function clear() { 
// 遍历目录清除缓存 
$cacheDir = $this->_cachesDir; 
$d = dir($cacheDir); 
while(false !== ($entry = $d->read())) { 
if('.' == $entry[0]) { 
continue; 
} 
$cacheEntry = $cacheDir . '/' . $entry; 
if(is_file($cacheEntry)) { 
@unlink($cacheEntry); 
} elseif(is_dir($cacheEntry)) { 
// 缓存文件夹有两级 
$d2 = dir($cacheEntry); 
while(false !== ($entry = $d2->read())) { 
if('.' == $entry[0]) { 
continue; 
} 
$cacheEntry .= '/' . $entry; 
if(is_file($cacheEntry)) { 
@unlink($cacheEntry); 
} 
} 
$d2->close(); 
} 
} 
$d->close(); 
return $this; 
} 
} 
/** 
* 缓存单元的数据结构 
* array( 
* 'time' => time(), // 缓存写入时的时间戳 
* 'expire' => $expire, // 缓存过期时间 
* 'valid' => true, // 缓存是否有效 
* 'data' => $value // 缓存的值 
* ); 
*/ 
final class Cache { 
/** 
* 缓存过期时间长度(s) 
* 
* @var int 
*/ 
private $_expire = 3600; 
/** 
* 缓存处理类 
* 
* @var Cache_Abstract 
*/ 
private $_storage = null; 
/** 
* @return Cache 
*/ 
static public function createCache($cacheClass = 'Cache_File') { 
return new self($cacheClass); 
} 
private function __construct($cacheClass) { 
$this->_storage = new $cacheClass(); 
} 
/** 
* 设置缓存 
* 
* @param string $key 
* @param mixed $value 
* @param int $expire 
*/ 
public function set($key, $value, $expire = false) { 
if (!$expire) { 
$expire = $this->_expire; 
} 
$this->_storage->checkLock($key); 
$data = array('time' => time(), 'expire' => $expire, 'valid' => true, 'data' => $value); 
$this->_storage->lock($key); 
try { 
$this->_storage->store($key, $data); 
$this->_storage->unlock($key); 
} catch (CacheException $e) { 
$this->_storage->unlock($key); 
throw $e; 
} 
} 
/** 
* 读取缓存 
* 
* @param string $key 
* @return mixed 
*/ 
public function get($key) { 
$data = $this->fetch($key); 
if ($data && $data['valid'] && !$data['isExpired']) { 
return $data['data']; 
} 
return false; 
} 
/** 
* 读缓存,包括过期的和无效的,取得完整的存贮结构 
* 
* @param string $key 
*/ 
public function fetch($key) { 
$this->_storage->checkLock($key); 
$data = $this->_storage->fetch($key); 
if ($data) { 
$data['isExpired'] = (time() - $data['time']) > $data['expire'] ? true : false; 
return $data; 
} 
return false; 
} 
/** 
* 删除缓存 
* 
* @param string $key 
*/ 
public function delete($key) { 
$this->_storage->checkLock($key) 
->lock($key) 
->delete($key) 
->unlock($key); 
} 
public function clear() { 
$this->_storage->clear(); 
} 
/** 
* 把缓存设为无效 
* 
* @param string $key 
*/ 
public function setInvalidate($key) { 
$this->_storage->checkLock($key) 
->lock($key); 
try { 
$data = $this->_storage->fetch($key); 
if ($data) { 
$data['valid'] = false; 
$this->_storage->store($key, $data); 
} 
$this->_storage->unlock($key); 
} catch (CacheException $e) { 
$this->_storage->unlock($key); 
throw $e; 
} 
} 
/** 
* 设置缓存过期时间(s) 
* 
* @param int $expire 
*/ 
public function setExpire($expire) { 
$this->_expire = (int) $expire; 
return $this; 
} 
}
PHP 相关文章推荐
global.php
Dec 09 PHP
php 无限级缓存的类的扩展
Mar 16 PHP
php学习之运算符相关概念
Jun 09 PHP
使用php实现下载生成某链接快捷方式的解决方法
May 07 PHP
解析关于wamp启动是80端口被占用的问题
Jun 21 PHP
php使用ICQ网关发送手机短信
Oct 30 PHP
PHP基于php_imagick_st-Q8.dll实现JPG合成GIF图片的方法
Jul 11 PHP
php通过修改header强制图片下载的方法
Mar 24 PHP
php常用字符串String函数实例总结【转换,替换,计算,截取,加密】
Dec 07 PHP
php正则判断是否为合法身份证号的方法
Mar 16 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
Jun 16 PHP
PHP 使用位运算实现四则运算的代码
Mar 09 PHP
PHP 防恶意刷新实现代码
May 16 #PHP
PHP 全角转半角实现代码
May 16 #PHP
php5.3 废弃函数小结
May 16 #PHP
memcached 和 mysql 主从环境下php开发代码详解
May 16 #PHP
php 中文和编码判断代码
May 16 #PHP
PHP URL地址获取函数代码(端口等) 推荐
May 15 #PHP
php select,radio和checkbox默认选择的实现方法
May 15 #PHP
You might like
php学习之变量的使用
2011/05/29 PHP
php重定向的三种方法分享
2012/02/22 PHP
Window 7/XP 安装Apache 2.4与PHP 5.4 的过程详解
2013/06/02 PHP
php实现微信支付之现金红包
2018/05/30 PHP
ThinkPHP5框架缓存查询操作分析
2018/05/30 PHP
PHP文件操作实例总结【文件上传、下载、分页】
2018/12/08 PHP
js左侧多级菜单动态的解决方案
2010/02/01 Javascript
jQuery JSON实现无刷新三级联动实例探讨
2013/05/28 Javascript
ExtJS DOM元素操作经验分享
2013/08/28 Javascript
javascript不同类型数据之间的运算的转换方法
2014/02/13 Javascript
JavaScript控制网页层收起和展开效果的方法
2015/04/15 Javascript
详解JavaScript中return的用法
2017/05/08 Javascript
微信小程序之swiper轮播图中的图片自适应高度的方法
2018/04/23 Javascript
解决axios发送post请求返回400状态码的问题
2018/08/11 Javascript
基于vue 动态菜单 刷新空白问题的解决
2020/08/06 Javascript
JavaScript实现滚动加载更多
2020/12/27 Javascript
聊聊vue 中的v-on参数问题
2021/01/29 Vue.js
JavaScript实现H5接金币功能(实例代码)
2021/02/22 Javascript
[55:18]Liquid vs Chaos 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
编写Python脚本批量下载DesktopNexus壁纸的教程
2015/05/06 Python
Python实现针对含中文字符串的截取功能示例
2017/09/22 Python
Python基于jieba库进行简单分词及词云功能实现方法
2018/06/16 Python
Python实现在某个数组中查找一个值的算法示例
2018/06/27 Python
Python如何创建装饰器时保留函数元信息
2020/08/07 Python
详解pycharm配置python解释器的问题
2020/10/15 Python
使用python-cv2实现视频的分解与合成的示例代码
2020/10/26 Python
使用HTML5的链接预取功能(link prefetching)给网站提速
2012/12/13 HTML / CSS
Crocs卡骆驰洞洞鞋日本官方网站:Crocs日本
2016/08/25 全球购物
如果让你测试一台高速激光打印机,你都会进行哪些测试
2012/12/04 面试题
高校学生干部的自我评价分享
2013/11/04 职场文书
军校本科大学生自我评价
2014/01/14 职场文书
2014年五四青年节演讲比赛方案
2014/04/22 职场文书
后备干部培训方案
2014/05/22 职场文书
政风行风评议整改方案
2014/09/15 职场文书
写给妈妈的感谢信
2015/01/22 职场文书
用JS创建一个录屏功能
2021/11/11 Javascript