php - apc和文件缓存类

// 收集到的一篇不错的PHP缓存实现。实现了apc和文件缓存,继承Cache_Abstract即可实现调用第三方的缓存工具。

<?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([url=mailto:!@mkdir($cacheDir]!@mkdir($cacheDir[/url], 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(empty($key)) {
         throw new CacheException("Missing argument 1 for Cache_File::delete()");
     }
     
     $cacheFile = self::_getCacheFile($key);
     if([url=mailto:!@unlink($cacheFile]!@unlink($cacheFile[/url])) {
         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([url=mailto:!@mkdir($cacheDir]!@mkdir($cacheDir[/url], 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;
}
}

标签: 缓存, 变量, IT, 下标