缓存技术详谈―php


Posted in PHP onDecember 14, 2006

一、引论

PHP,一门最近几年兴起的web设计脚本语言,由于它的强大 和可伸缩性,近几年来得到长足的发展,php相比传统的asp网站,在速度上有绝对的优势,想mssql转6万条数据php如需要40秒,asp不下2分 钟.但是,由于网站的数据越来越多,我们渴求能更快速的调用数据,不必要每次都从数据库掉,我们可以从其他的地方,比方一个文件,或者某个内存地址,这就 是php的缓存技术,也就是Cache技术.

二、分析深入

一般来说,缓存的目的是把数据放在一个地方让访问的更快点,毫 无疑问,内存是最快的,但是,几百M的数据能往内存放么?这不现实,当然,有的时候临时放如服务器缓存,如ob_start()这个缓存页面开启的话在发 送文件头之前页面内容都被缓存在内存中,知道等页面输出自动清楚或者等待ob_get_contents的返回,或者被ob_end_clean显示的清 除,这在静态页面的生成中能很好的利用,在模板中能得到很好的体现,这是一种方式,但这是临时性的,不是解决我们问题的好方法.

另外,在 asp中有一对象application,可以保存公用的参数,这也算点缓存,但在php,我至今没看到开发者产出这种对象,的确,没必要. asp.net的页面缓存技术就用的是viewstate,而cache就是文件关联,(不一定准确),文件被修改,更新缓存,文件没被修改而且不超时 (注释1),就读取缓存,返回结果,就是这个思路,看看这个源码:

PHP:[Copy to clipboard]
<?php
class cache{
/*
Class Name: cache
Description: control to cache data,$cache_out_time is a array to save cache date time out.
Version: 1.0
Author: 老农 cjjer
Last modify:2006-2-26
Author URL: http://www.cjjer.com
*/
private $cache_dir;
private $expireTime=180;//缓存的时间是 60 秒
function __construct($cache_dirname){
 if(!@is_dir($cache_dirname)){
  if(!@mkdir($cache_dirname,0777)){
  $this->warn('缓存文件不存在而且不能创建,需要手动创建.');
  return false;
  }
 }
$this->cache_dir = $cache_dirname;
}
function __destruct(){
 echo 'Cache class bye.';
}

function get_url() {
        if (!isset($_SERVER['REQUEST_URI'])) {
                $url = $_SERVER['REQUEST_URI'];
        }else{
                $url = $_SERVER['SCRIPT_NAME'];
                $url .= (!empty($_SERVER['QUERY_STRING'])) ? '?' . $_SERVER['QUERY_STRING'] : '';
        }

        return $url;
}

function warn($errorstring){
echo "<b><font color='red'>发生错误:<pre>".$errorstring."</pre></font></b>";
}

function cache_page($pageurl,$pagedata){
 if(!$fso=fopen($pageurl,'w')){
  $this->warns('无法打开缓存文件.');//trigger_error
  return false;
 }
 if(!flock($fso,LOCK_EX)){//LOCK_NB,排它型锁定
  $this->warns('无法锁定缓存文件.');//trigger_error
  return false;
 }
 if(!fwrite($fso,$pagedata)){//写入字节流,serialize写入其他格式
  $this->warns('无法写入缓存文件.');//trigger_error
  return false;
 }
 flock($fso,LOCK_UN);//释放锁定
 fclose($fso);
 return true;
}

function display_cache($cacheFile){
            if(!file_exists($cacheFile)){
    $this->warn('无法读取缓存文件.');//trigger_error
    return false;
            }
   echo '读取缓存文件:'.$cacheFile;
//return unserialize(file_get_contents($cacheFile));
        $fso = fopen($cacheFile, 'r');
        $data = fread($fso, filesize($cacheFile));
        fclose($fso);
 return $data;
}

function readData($cacheFile='default_cache.txt'){
 $cacheFile = $this->cache_dir."/".$cacheFile;
 if(file_exists($cacheFile)&&filemtime($cacheFile)>(time()-$this->expireTime)){
  $data=$this->display_cache($cacheFile);
  }else{
   $data="from here wo can get it from mysql database,update time is <b>".date('l dS of F Y h:i:s A')."</b>,过期时间是:".date('l dS of F Y h:i:s A',time()+$this->expireTime)."----------";
   $this->cache_page($cacheFile,$data);
 }
  return $data;
}

}
?> 

下面我打断这个代码逐行解释.

三、程序透析

这个缓存类(类没什么好怕的.请继续看)名称是cache,有2个属性:

CODE:[Copy to clipboard]private $cache_dir;
private $expireTime=180;
$cache_dir是缓存文件所放的相对网站目录的父目录, $expireTime(注释一)是我们缓存的数据过期的时间,主要是这个思路:
当数据或者文件被加载的时候,先判断缓存文件存在不,返回false ,文件最后修改时间和缓存的时间和比当前时间大不,大的话说明缓存还没到期,小的话返回false,当返回false的时候,读取原始数据,写入缓存文件中,返回数据.

接着看程序:

PHP:[Copy to clipboard]
function __construct($cache_dirname){
 if(!@is_dir($cache_dirname)){
  if(!@mkdir($cache_dirname,0777)){
  $this->warn('缓存文件不存在而且不能创建,需要手动创建.');
  return false;
  }
 }
$this->cache_dir = $cache_dirname;

当类第一次被实例的时候构造默认函数带参数缓存文件名称,如文件不存在,创建一个有编辑权限的文件夹,创建失败的时候抛出异常.然后把cache类的 $cache_dir属性设置为这个文件夹名称,我们的所有缓存文件都是在这个文件夹下面的.

PHP:[Copy to clipboard]
function __destruct(){
 echo 'Cache class bye.';

这是class类的析构函数,为了演示,我们输出一个字符串表示我们释放cache类资源成功.

PHP:[Copy to clipboard]
function warn($errorstring){
echo "<b><font color='red'>发生错误:<pre>".$errorstring."</pre></font></b>";

这个方法输出错误信息.

PHP:[Copy to clipboard]
function get_url() {
        if (!isset($_SERVER['REQUEST_URI'])) {
                $url = $_SERVER['REQUEST_URI'];
        }else{
                $url = $_SERVER['SCRIPT_NAME'];
                $url .= (!empty($_SERVER['QUERY_STRING'])) ? '?' . $_SERVER['QUERY_STRING'] : '';
        }

        return $url;

这个方法返回当前url的信息,这是我看国外很多人的cms系统这样做,主要是缓存x.php?page=1,x.php?page=2,等这种文件的,这里列出是为了扩展的这个cache类功能的.

PHP:[Copy to clipboard]
function cache_page($pageurl,$pagedata){
 if(!$fso=fopen($pageurl,'w')){
  $this->warns('无法打开缓存文件.');//trigger_error
  return false;
 }
 if(!flock($fso,LOCK_EX)){//LOCK_NB,排它型锁定
  $this->warns('无法锁定缓存文件.');//trigger_error
  return false;
 }
 if(!fwrite($fso,$pagedata)){//写入字节流,serialize写入其他格式
  $this->warns('无法写入缓存文件.');//trigger_error
  return false;
 }
 flock($fso,LOCK_UN);//释放锁定
 fclose($fso);
 return true;

cache_page方法分别传入的是缓存的文件名称和数据,这是把数据写到文件里的方法,先用fopen打开文件,然后调用句柄锁定这个文件,然后用fwrite写入文件,最后释放这个句柄,任何一步发生错误将抛出错误. 您可能看到这个注释:

写入字节流,serialize写入其他格式
顺便一提的是如果我们要把一个数组,(可以从MySQL数据库里面select查询除了的结果)用serialize函数写入,用unserialize读取到原来的类型.

PHP:[Copy to clipboard]
function display_cache($cacheFile){
            if(!file_exists($cacheFile)){
    $this->warn('无法读取缓存文件.');//trigger_error
    return false;
            }
   echo '读取缓存文件:'.$cacheFile;
//return unserialize(file_get_contents($cacheFile));
        $fso = fopen($cacheFile, 'r');
        $data = fread($fso, filesize($cacheFile));
        fclose($fso);
 return $data;

这是由文件名称读取缓存的方法,直接打开文件,读取全部,如果文件不存在的或者无法读取的话返回false,当然,你感到不人性的话,可以重新生成缓存.

function readData($cacheFile='default_cache.txt'){
 $cacheFile = $this->cache_dir."/".$cacheFile;
 if(file_exists($cacheFile)&&filemtime($cacheFile)>(time()-$this->expireTime)){
  $data=$this->display_cache($cacheFile);
  }else{
   $data="from here wo can get it from mysql database,update time is <b>".date('l dS of F Y h:i:s A')."</b>,过期时间是:".date('l dS of F Y h:i:s A',time()+$this->expireTime)."----------";
   $this->cache_page($cacheFile,$data);
 }
  return $data;

这 个函数是我们调用的方法,可以写成接口的方法,由传入参数判断文件存在不,文件最后修改时间+expireTime的时间是不是过了当前时间(大于的话说 明没有过期),如果文件不存在或者已经过期,重新加载原始数据,这里,为了简单期间,我们是直接源是字符串,您可以把cache类继承某类,取到数据库的 数据.(注释2)

四、补充说明,结语 

注释一:这个缓存的时间您可以自己调,可以根据时间情况读取数组,xml,缓存等,请按照您的方便,值得一提的是缓存的时间(也就是缓存的key)也用缓存控制,.这在cms系统中被广泛使用,他们把要更新的key放在缓存中,非常容易控制全战.

注释二:php5开始支持类继承,这是让人兴奋的,把网站全局休息写在一个配置的类里面,再写与数据层交互的类(如与MySQL交互的类),我们的这个cache类继承数据交互的类,可以非常容易的读取数据库,这是外话,此处不再展开,有时间和大家详谈.

特别说明,这个类文件针对的php5以上版本,其他版本的请不要使用类. 

PHP 相关文章推荐
一个用于mysql的数据库抽象层函数库
Oct 09 PHP
php.ini 中文版
Oct 28 PHP
PHP实现使用优酷土豆视频地址获取swf播放器分享地址
Jun 05 PHP
Codeigniter生成Excel文档的简单方法
Jun 12 PHP
浅谈php命令行用法
Feb 04 PHP
php实现word转html的方法
Jan 22 PHP
yii2整合百度编辑器umeditor及umeditor图片上传问题的解决办法
Apr 20 PHP
php写一个函数,实现扫描并打印出自定目录下(含子目录)所有jpg文件名
May 26 PHP
PHP长连接实现与使用方法详解
Feb 11 PHP
PHP实现的XXTEA加密解密算法示例
Aug 28 PHP
PHP设计模式之观察者模式定义与用法分析
Apr 04 PHP
Yii框架通过请求组件处理get,post请求的方法分析
Sep 03 PHP
PHP面向对象编程快速入门
Dec 14 #PHP
Breeze 文章管理系统 v1.0.0正式发布
Dec 14 #PHP
谈谈新手如何学习PHP
Dec 14 #PHP
php基础知识:类与对象(5) static
Dec 13 #PHP
php基础知识:类与对象(4) 范围解析操作符(::)
Dec 13 #PHP
php基础知识:类与对象(3) 构造函数和析构函数
Dec 13 #PHP
php基础知识:类与对象(2) 自动加载对象
Dec 13 #PHP
You might like
PHP实现的简单缓存类
2015/07/29 PHP
利用PHPExcel读取Excel的数据和导出数据到Excel
2017/05/12 PHP
用javascript实现分割提取页面所需内容
2007/05/09 Javascript
jquery.validate分组验证代码
2011/03/17 Javascript
JS TextArea字符串长度限制代码集合
2012/10/31 Javascript
js如何判断访问是来自搜索引擎(蜘蛛人)还是直接访问
2015/09/14 Javascript
基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍
2016/05/12 Javascript
AngularJS 作用域详解及示例代码
2016/08/17 Javascript
JS判断是否为JSON对象及是否存在某字段的方法(推荐)
2016/11/29 Javascript
概述一个页面从输入URL到页面加载完的过程
2016/12/16 Javascript
vue .sync修饰符的使用详解
2018/06/15 Javascript
vue.js实现的绑定class操作示例
2018/07/06 Javascript
关于RxJS Subject的学习笔记
2018/12/05 Javascript
微信小程序webview实现长按点击识别二维码功能示例
2019/01/24 Javascript
Koa 中的错误处理解析
2019/04/09 Javascript
node.js中 mysql 增删改查操作及async,await处理实例分析
2020/02/11 Javascript
python list语法学习(带例子)
2013/11/01 Python
python通过加号运算符操作列表的方法
2015/07/28 Python
Python最火、R极具潜力 2017机器学习调查报告
2017/12/11 Python
python单例模式的多种实现方法
2019/07/26 Python
Python绘图实现台风路径可视化代码实例
2020/10/23 Python
Python3中小括号()、中括号[]、花括号{}的区别详解
2020/11/15 Python
CSS3移动端vw+rem不依赖JS实现响应式布局的方法
2019/01/23 HTML / CSS
阿根廷旅游网站:almundo阿根廷
2018/02/12 全球购物
英国版MAC彩妆品牌:Illamasqua
2018/04/18 全球购物
意大利拉斐尔时尚购物网:Raffaello Network(支持中文)
2018/11/09 全球购物
法国体育用品商店:GO Sport
2019/10/23 全球购物
建筑总经理岗位职责
2014/02/02 职场文书
大学生素质拓展活动方案
2014/02/11 职场文书
物业品质提升方案
2014/06/08 职场文书
慰问信范文
2015/02/14 职场文书
环卫工作个人总结
2015/03/04 职场文书
体育委员竞选稿
2015/11/21 职场文书
opencv 分类白天与夜景视频的方法
2021/06/05 Python
Python实现位图分割的效果
2021/11/20 Python
索尼ICF-5900W收音机测评
2022/04/24 无线电