首先在ThinkPHP的核心类库中定一个Cache的基类,以ThinkPHP3.1.3为例:
//文件地址:D:\code\ThinkPHP3.1.3\Lib\Core\Cache.class.php
class Cache {
protected $handler;
protected $options = array();
public function connect($type='',$options=array()) {
if(empty($type)) $type = C('DATA_CACHE_TYPE');
$type = strtolower(trim($type));
$class = 'Cache'.ucwords($type);
if(class_exists($class))
$cache = new $class($options);
else
throw_exception(L('_CACHE_TYPE_INVALID_').':'.$type);
return $cache;
}
public function __get($name) {
return $this->get($name);
}
public function __set($name,$value) {
return $this->set($name,$value);
}
public function __unset($name) {
$this->rm($name);
}
public function setOptions($name,$value) {
$this->options[$name] = $value;
}
public function getOptions($name) {
return $this->options[$name];
}
static function getInstance() {
$param = func_get_args();
return get_instance_of(__CLASS__,'connect',$param);
}
//队列缓存,下篇笔记
protected function queue($key) {
}
public function __call($method,$args){
//调用缓存类型自己的方法
if(method_exists($this->handler, $method)){
return call_user_func_array(array($this->handler,$method), $args);
}else{
throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
return;
}
}
}
在其中定义了connect,__set,__get等方法,保证其他具体的缓存类(子类)在继承该类之后存取缓存数据传入的参数是一致的,保证了系统平滑切换可以缓存。而在该方法里面并没有写直接写set和get方法,而是让__call方法去调用子类里面的这些方法。
ThinkPHP在对实例化对象方面也做了缓存优化,就是通过函数get_instance_of来保证了在一个进程中一个相同的对象只被实例化一次(ThinkPHP类似的优化有很多,比如文件的加载与包含等,说到底就是使用了static变量来缓存一些数据)。
我们知道在ThinkPHP中定义个S函数来做缓存操作:
function S($name,$value='',$options=null) {
static $cache = '';
if(is_array($options) && empty($cache)){
// 缓存操作的同时初始化
$type = isset($options['type'])?$options['type']:'';
$cache = Cache::getInstance($type,$options);
}elseif(is_array($name)) { // 缓存初始化
$type = isset($name['type'])?$name['type']:'';
$cache = Cache::getInstance($type,$name);
return $cache;
}elseif(empty($cache)) { // 自动初始化
$cache = Cache::getInstance();
}
if(''=== $value){ // 获取缓存
return $cache->get($name);
}elseif(is_null($value)) { // 删除缓存
return $cache->rm($name);
}else { // 缓存数据
if(is_array($options)) {
$expire = isset($options['expire'])?$options['expire']:NULL;
}else{
$expire = is_numeric($options)?$options:NULL;
}
return $cache->set($name, $value, $expire);
}
}
通过Cache::getInstance来实例化对象
/**
* 取得缓存类实例
* @static
* @access public
* @return mixed
*/
static function getInstance() {
$param = func_get_args();
return get_instance_of(__CLASS__,'connect',$param);
}
步入正题,到对象实例化的步骤:
/**
* 取得对象实例 支持调用类的静态方法
* @param string $name 类名
* @param string $method 方法名,如果为空则返回实例化对象
* @param array $args 调用参数
* @return object
*/
/**
* 以下面几个参数为例
* $name = Cache
* $method = connect
* $args = array(
* 'type'=>'memcache',
* 'options'=>array (
* 'host' => '127.0.0.1',
* 'port' => 11211,
* 'timeout' => false,
* 'persistent' => false,
* )
* )
*/
function get_instance_of($name, $method='', $args=array()) {
static $_instance = array();
$identify = empty($args) ? $name . $method : $name . $method . to_guid_string($args);
if (!isset($_instance[$identify])) {
if (class_exists($name)) {
$o = new $name();
if (method_exists($o, $method)) {
if (!empty($args)) {
$_instance[$identify] = call_user_func_array(array(&$o, $method), $args);
} else {
$_instance[$identify] = $o->$method();
}
}
else
$_instance[$identify] = $o;
}
else
halt(L('_CLASS_NOT_EXIST_') . ':' . $name);
}
return $_instance[$identify];
}
然后再实例化\ThinkPHP3.1.3\Extend\Driver\Cache\里面的各种类,以memcache的为例:
class CacheMemcache extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
function __construct($options=array()) {
if ( !extension_loaded('memcache') ) {
throw_exception(L('_NOT_SUPPERT_').':memcache');
}
$options = array_merge(array (
'host' => C('MEMCACHE_HOST') ? C('MEMCACHE_HOST') : '127.0.0.1',
'port' => C('MEMCACHE_PORT') ? C('MEMCACHE_PORT') : 11211,
'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false,
'persistent' => false,
),$options);
$this->options = $options;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$func = $options['persistent'] ? 'pconnect' : 'connect';
$this->handler = new Memcache;
$options['timeout'] === false ?
$this->handler->$func($options['host'], $options['port']) :
$this->handler->$func($options['host'], $options['port'], $options['timeout']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return $this->handler->get($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if($this->handler->set($name, $value, 0, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name, $ttl = false) {
$name = $this->options['prefix'].$name;
return $ttl === false ?
$this->handler->delete($name) :
$this->handler->delete($name, $ttl);
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return $this->handler->flush();
}
}