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

2015-01-24信息快讯网

PHP缓存实现,实现了apc和文件缓存,继承Cache_Abstract即可实现调用第三方的缓存工具。参考shindig的缓存类和apc。

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; 
} 
} 
©2014-2024 dbsqp.com