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 相关文章推荐
用Zend Encode编写开发PHP程序
Oct 09 PHP
从一个不错的留言本弄的mysql数据库操作类
Sep 02 PHP
yii实现CheckBox复选框在同一行显示的方法
Dec 03 PHP
php判断输入是否是纯数字,英文,汉字的方法
Mar 05 PHP
详解WordPress中提醒安装插件以及隐藏插件的功能实现
Dec 25 PHP
又拍云异步上传实例教程详解
Apr 19 PHP
Laravel与CI框架中截取字符串函数
May 08 PHP
ThinkPHP实现更新数据实例详解(demo)
Jun 29 PHP
yii2 commands模式以及配置crontab定时任务的方法
Aug 19 PHP
php 读写json文件及修改json的方法
Mar 07 PHP
yii2.0框架多模型操作示例【添加/修改/删除】
Apr 13 PHP
Thinkphp5框架中引入Markdown编辑器操作示例
Jun 03 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数据采集的详解
2013/06/02 PHP
YII Framework框架教程之安全方案详解
2016/03/14 PHP
详解配置 Apache 服务器支持 PHP 文件的解析
2017/02/15 PHP
php5.3/5.4/5.5/5.6/7常见新增特性汇总整理
2020/02/27 PHP
Javascript操作select方法大全[新增、修改、删除、选中、清空、判断存在等]
2008/09/26 Javascript
JavaScript中数组的排序、乱序和搜索实现代码
2011/11/30 Javascript
JQuery中判断一个元素下面是否有内容或者有某个标签的判断代码
2012/02/02 Javascript
Js四则运算函数代码
2012/07/21 Javascript
基于JavaScript 下namespace 功能的简单分析
2013/07/05 Javascript
jquery实现输入框动态增减的实例代码
2013/07/14 Javascript
Javascript实现真实字符串剩余字数提示的实例代码
2013/10/22 Javascript
javascript实现的HashMap类代码
2014/06/27 Javascript
js实现按钮加背景图片常用方法
2014/11/01 Javascript
js实现百度联盟中一款不错的图片切换效果完整实例
2015/03/04 Javascript
JS基于HTML5的canvas标签实现炫目的色相球动画效果实例
2016/08/24 Javascript
JavaScript制作弹出层效果
2016/12/02 Javascript
一篇看懂vuejs的状态管理神器 vuex状态管理模式
2017/04/20 Javascript
nuxt框架中路由鉴权之Koa和Session的用法
2018/05/09 Javascript
vue项目实现github在线预览功能
2018/06/20 Javascript
JavaScript实现简单的隐藏式侧边栏功能示例
2018/08/31 Javascript
[01:01:24]LGD vs Fnatic 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
python 字符串split的用法分享
2013/03/23 Python
python判断字符串是否包含子字符串的方法
2015/03/24 Python
python实现多线程的方式及多条命令并发执行
2016/06/07 Python
Django如何自定义model创建数据库索引的顺序
2019/06/20 Python
Python中如何引入第三方模块
2020/05/27 Python
python 制作python包,封装成可用模块教程
2020/07/13 Python
python中uuid模块实例浅析
2020/12/29 Python
微软开源最强Python自动化神器Playwright(不用写一行代码)
2021/01/05 Python
final, finally, finalize的区别
2012/03/01 面试题
大二学生职业生涯规划书
2014/02/05 职场文书
汉语言文学专业自荐信
2014/06/11 职场文书
民事诉讼代理委托书
2014/10/08 职场文书
伊索寓言读书笔记
2015/06/30 职场文书
vue3如何优雅的实现移动端登录注册模块
2021/03/29 Vue.js
纯html+css实现奥运五环的示例代码
2021/08/02 HTML / CSS