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

代码如下:

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;
}
}

(0)

相关推荐

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

    复制代码 代码如下: class CacheException extends Exception {} /** * 缓存抽象类 */ abstract class Cache_Abstract { /** * 读缓存变量 * * @param string $key 缓存下标 * @return mixed */ abstract public function fetch($key); /** * 缓存变量 * * @param string $key 缓存变量下标 * @param str

  • PHP 图片上传实现代码 带详细注释

    复制代码 代码如下: <?php //用户上传图片处理文件 if ((($_FILES["file"]["type"] == "image/gif")|| ($_FILES["file"]["type"] == "image/jpeg")|| ($_FILES["file"]["type"] == "image/pjpeg"

  • 一个PHP缓存类代码(附详细说明)

    复制代码 代码如下: <?php define('CACHE_ROOT', dirname(__FILE__).'/cache'); //缓存存放目录 define('CACHE_TIME', 1800);//缓存时间 单位秒 define('CACHE_FIX','.html'); $CacheName=md5($_SERVER['REQUEST_URI']).CACHE_FIX; //缓存文件名 $CacheDir=CACHE_ROOT.'/'.substr($CacheName,0,1);

  • ThinkPHP文件缓存类代码分享

    取自ThinkPHP的文件缓存类代码,这里就不多废话了,小伙伴们自己看注释吧. <?php /** * @desc 文件缓存 */ class Cache{ const C_FILE = '/Runtime/'; private $dir = ''; const EXT = '.tpl'; private $filename = ''; public function __construct($dir = ''){ $this->dir = $dir; } /** * @desc 设置文件缓存

  • asp清理缓存的代码

    复制代码 代码如下: <% Response.Buffer = True '一般情况下,当用户请求WEB服务器时,服务器把请求回复给客户端.在客户端,浏览器把缓存作为一种加快速度的策略,就是当请求时先检查缓存的情况,如果有就直接调缓存了,而不请求服务器了. '在WEB程序设计中,有时为了防止重复的提交或者严格的次序等,必须让用户的数据立即在使用后就过期,当用户后退时就显示过期而不能继续使用.一般,response.expires写在页面的最上端,后面跟的是过期的时间,0,-1表示立即过期. 'a

  • Jquery实现瀑布流布局(备有详细注释)

    本文实例讲述了Jquery实现瀑布流布局的方法.分享给大家供大家参考.具体如下: 瀑布流布局最近真的很流行,很多人都跟我一样想知道是怎么做出来的吧,经过网上搜索大量的参考结合N边的实验今天终于被我写出来了,为了便于大家理解我使用了jQuery(当然用源生js代码执行的效率会高一些,但是很多人多源生js不是很熟练). <!doctype html> <html> <head> <meta charset="utf-8"> <title

  • IDEA中项目集成git提交代码的详细步骤

    简介:在团队协作开发的过程中,好的代码管理能更加有效的使日常开发的过程中对各个开发人员提高开发速度.下面将详细介绍在IDEA中使用git提交代码的过程: 一:pull代码 在提交代码之前,我们必须先对代码就行更新操作,这一步非常重要,如果不进行更新代码操作,当有其他小伙伴有更改的内容已经提交到代码仓库但是我们本地缺没有更新的话,就会造成我们提交的代码跟别人已提交过的代码产生冲突(使用git解决冲突会比较麻烦,在这里就不进行讲解了,后期会单独更新).即使我们解决了冲突,也可能会冲掉别人的代码,造成

  • IDEA插件之快速删除Java代码中的注释

    背景 有时,我们需要删除Java源代码中的注释.目前有不少方法,比如: 实现状态机.该方式较为通用,适用于多种语言(取决于状态机支持的注释符号). 正则匹配.该方式容易误判,尤其是容易误删字符串. 利用第三方库.该方式局限性较强,比如不同语言可能有不同的第三方库. 本文针对Java语言,介绍一种利用第三方库的方式,可以方便快速地移除代码中的注释. 原理 这个第三方库叫做JavaParser.它可以分析Java源码,并生成语法分析树(AST),其中注释也属于AST中的节点. 因此核心思路即为: J

  • Pytorch实现图像识别之数字识别(附详细注释)

    使用了两个卷积层加上两个全连接层实现 本来打算从头手撕的,但是调试太耗时间了,改天有时间在从头写一份 详细过程看代码注释,参考了下一个博主的文章,但是链接没注意关了找不到了,博主看到了联系下我,我加上 代码相关的问题可以评论私聊,也可以翻看博客里的文章,部分有详细解释 Python实现代码: import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transf

  • 超详细注释之OpenCV dlib实现人脸采集

    上一篇博客中,我们了解了什么是面部标志,以及如何使用dlib,OpenCV和Python检测它们.利用dlib的HOG SVM的形状预测器获得面部ROI中面部区域的68个点(x,y)坐标. 这一篇博客中,将演示如何使用NumPy数组切片魔术来分别访问每个面部部分并提取眼睛,眉毛,鼻子,嘴巴和下巴的特征. 1. 效果图 先上一张检测完的图: 也可以每一部分先标识出来: 2. 原理 面部标志主要是: 口 右眉 左眉 右眼 左眼 鼻子 下颚线 这一节即提取这些部分: 从图中可以看到假设是以0为下标的数

随机推荐