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 相关文章推荐
php 保留字列表
Oct 04 PHP
关于js与php互相传值的介绍
Jun 25 PHP
php统计时间和内存使用情况示例分享
Mar 13 PHP
浅谈PHP调用Webservice思路及源码分享
Jun 04 PHP
php数组添加元素方法小结
Dec 20 PHP
php将access数据库转换到mysql数据库的方法
Dec 24 PHP
PHP中的替代语法介绍
Jan 09 PHP
[原创]php常用字符串输出方法分析(echo,print,printf及sprintf)
Jul 09 PHP
php 替换文章中的图片路径,下载图片到本地服务器的方法
Feb 06 PHP
PHP手机短信验证码实现流程详解
May 17 PHP
PHP中抽象类,接口功能、定义方法示例
Feb 26 PHP
Laravel 将数据表的数据导出,并生成seeds种子文件的方法
Oct 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+Ajax实现唯一校验实现代码[简单应用]
2011/11/29 PHP
php的ZipArchive类用法实例
2014/10/20 PHP
完美解决thinkphp验证码出错无法显示的方法
2014/12/09 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
Javascript实例教程(19) 使用HoTMetal(2)
2006/12/23 Javascript
javascript 一个自定义长度的文本自动换行的函数
2007/08/19 Javascript
JavaScript函数、方法、对象代码
2008/10/29 Javascript
精通Javascript系列之数值计算
2011/06/07 Javascript
jquery ajax 简单范例(界面+后台)
2013/11/19 Javascript
深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解
2015/03/05 Javascript
对JavaScript的全文搜索实现相关度评分的功能的方法
2015/06/24 Javascript
JavaScript Length 属性的总结
2015/11/02 Javascript
JavaScript时间操作之年月日星期级联操作
2016/01/15 Javascript
JavaScript获取对象在页面中位置坐标的方法
2016/02/03 Javascript
jQuery日历插件datepicker用法详解
2016/03/03 Javascript
Bootstrap 实现查询的完美方法
2016/10/26 Javascript
深入理解选择框脚本[推荐]
2016/12/13 Javascript
vue router路由嵌套不显示问题的解决方法
2017/06/17 Javascript
vue 组件 全局注册和局部注册的实现
2018/02/28 Javascript
Vue.js实现开发购物车功能的方法详解
2019/02/22 Javascript
Vue强制组件重新渲染的方法讨论
2020/02/03 Javascript
在Python中使用swapCase()方法转换大小写的教程
2015/05/20 Python
详解Python中的Numpy、SciPy、MatPlotLib安装与配置
2017/11/17 Python
python实现简易云音乐播放器
2018/01/04 Python
创建pycharm的自定义python模板方法
2018/05/23 Python
Django 中使用流响应处理视频的方法
2018/07/20 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
HTML5未来发展趋势
2016/02/01 HTML / CSS
lululemon美国官网:瑜伽服+跑步装备
2018/11/16 全球购物
索桥的故事教学反思
2014/02/06 职场文书
奥巴马竞选演讲稿
2014/05/15 职场文书
综合测评个人总结
2015/03/03 职场文书
小学重阳节活动总结
2015/03/24 职场文书
毕业论文致谢词
2015/05/14 职场文书
想创业成功,需要掌握这些要点
2019/12/06 职场文书
PHP 技巧 * SVG 保存为图片(分享图生成)
2021/04/02 PHP