当前位置:  开发笔记 > 编程语言 > 正文

深入探讨PHP缓存技术

PHP,一门最近几年兴起的Web设计脚本语言,由于它的强大和可伸缩性,近几年来得到长足的发展,PHP相比传统的ASP网站,在速度上有绝对的优势,想mssql转6万条数据PHP如需要40秒,ASP不下2分钟.但是,由于网站的数据越...">

  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),就读取缓存,返回结果,就是这个思路,看看这个源码:

 

  

  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 "发生错误:

".$errorstring."
";

  }

  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 ".date('l dS \of F Y h:i:s A').",过期时间是:".date('l dS \of F Y h:i:s A',time()+$this->expireTime)."----------";

  $this->cache_page($cacheFile,$data);

  }

  return $data;

  }

  }

  ?>

 

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

 

  程序透析

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

  private $cache_dir;

private $expireTime=180;

  $cache_dir是缓存文件所放的相对网站目录的父目录, $expireTime(注释一)是我们缓存的数据过期的时间,主要是这个思路:

  当数据或者文件被加载的时候,先判断缓存文件存在不,返回false ,文件最后修改时间和缓存的时间和比当前时间大不,大的话说明缓存还没到期,小的话返回false,当返回false的时候,读取原始数据,写入缓存文件中,返回数据。接着看程序:

 

  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属性设置为这个文件夹名称,我们的所有缓存文件都是在这个文件夹下面的.

 

  function __destruct(){ echo 'Cache class bye.'; }

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

    function warn($errorstring){ 
    echo "发生错误:

".$errorstring."
"; 
    }

 

  这个方法输出错误信息:

 

  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类功能的。

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读取到原来的类型。

 

  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 ".date('l dS \of F Y h:i:s A').",过期时间是:".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类继承数据交互的类,可以非常容易的读取数据库,这是外话,此处不再展开,有时间和大家详谈。


推荐阅读
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • 如何使用Python高效绘制矩形图形
    本文详细介绍了如何利用Python的Turtle库高效绘制矩形图形,适合初学者快速上手。通过具体示例代码,帮助读者理解Turtle库的基本绘图方法和技巧,同时探讨了在不同应用场景中绘制矩形的实际操作,为后续复杂图形的绘制打下坚实基础。 ... [详细]
  • 通过自定义 `TextView`,实现了在用户点击或焦点变化时动态调整字体颜色的效果。该方法利用了 `ColorStateList` 和 `Selector` 资源文件,确保了界面交互的流畅性和视觉效果的提升。具体实现中,通过重写 `onTouchEvent` 和 `onFocusChanged` 方法,精确控制了颜色变化的时机和状态。此外,还对性能进行了优化,确保在高频率操作下依然保持高效响应。 ... [详细]
  • 在第六章中,我们将深入探讨MySQL中的多表查询技术,包括联结查询和子查询。联结查询通过将两个或多个表进行连接,基于连接条件生成结果集。常见的联结类型有内联结、外联结和全外联结。交叉联结(CROSS JOIN)虽然使用较少,但其原理是生成所有可能的组合,类似于笛卡尔积的概念。此外,子查询则是在一个查询语句中嵌套另一个查询,用于获取更复杂的数据集。本章将通过实例详细讲解这些查询方法的应用和优化技巧。 ... [详细]
  • 如何在Oracle ASM_Diskgroup中重命名现有磁盘
    如何在Oracle ASM_Diskgroup中重命名现有磁盘 ... [详细]
  • 解决基于XML配置的MyBatis在Spring整合中出现“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”问题的方法
    在将Spring与MyBatis进行整合时,作者遇到了“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”的问题。该问题主要出现在使用XML文件配置DAO层的情况下,而注解方式配置则未出现类似问题。作者详细分析了两个配置文件之间的差异,并最终找到了解决方案。本文将详细介绍问题的原因及解决方法,帮助读者避免类似问题的发生。 ... [详细]
  • 在探讨如何高效处理大规模数据报表的分页展示之前,首先需要明确导致报表加载缓慢的主要原因。通常情况下,这主要是由于两个方面:一是查询条件过于宽泛,使得数据库返回的结果集包含数百万甚至更多的记录;二是前端渲染性能不足,无法高效处理大量数据。为了优化这一过程,可以从以下几个方面入手:优化查询条件,减少不必要的数据返回;采用分页查询技术,每次仅加载所需的数据;利用缓存机制,减少对数据库的频繁访问;提升前端渲染效率,使用虚拟滚动等技术提高用户体验。 ... [详细]
  • Issue with the Reserved Term HOSTS in System Configuration ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • 深入解析:Explain命令的应用与字段详解
    深入解析:Explain命令的应用与字段详解 ... [详细]
  • 本文详细解析了如何使用 jQuery 实现一个在浏览器地址栏运行的射击游戏。通过源代码分析,展示了关键的 JavaScript 技术和实现方法,并提供了在线演示链接供读者参考。此外,还介绍了如何在 Visual Studio Code 中进行开发和调试,为开发者提供了实用的技巧和建议。 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 如何将PHP文件上传至服务器及正确配置服务器地址 ... [详细]
  • 浅析PHP中$_SERVER[
    在PHP后端开发中,`$_SERVER["HTTP_REFERER"]` 是一个非常有用的超级全局变量,它可以获取用户访问当前页面之前的URL。本文将详细介绍该变量的使用方法及其在不同场景下的应用,如页面跳转跟踪、安全验证和用户行为分析等。通过实例解析,帮助开发者更好地理解和利用这一功能。 ... [详细]
  • 从用户转型为开发者:一场思维升级的旅程 | 专访 StarRocks Committer 周威
    从用户转变为开发者,不仅是一次角色的转换,更是一场深刻的思维升级之旅。本次专访中,StarRocks Committer 周威分享了他如何在这一过程中逐步提升技术能力与思维方式,为开源社区贡献自己的力量。 ... [详细]
author-avatar
营帐水狂_836
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有