当前位置: 首页 > news >正文

PHP简易的缓存实现思路

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

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

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

class cache { 
/* 
Class Name: cache 
Description: control to cache data,$cache_out_time is a array to save cache date time out. 
*/ 

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; 
} 

} 
?>

这个缓存类有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类继承某类, 取到数据库的数据。

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

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

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

转载于:https://my.oschina.net/kalcaddle/blog/55849

相关文章:

  • Ubuntu下安装Cacti+rrdtool监控Windows
  • 整理:IE6浏览器下容器boder消失的解决办法
  • 有向无环图
  • linux服务器集群运维经验
  • jsbeautifier + JScript.NET/JavaScript 编程实现 JavaScript、HTML、CSS 代码格式化脚本命令行工具 并集成到 EditPlus...
  • Python实现简单接口自动化测试
  • Codeforces Round #428 (Div. 2)
  • 【转】搜索算法的剪枝优化
  • vue.js过渡效果之--javascript钩子
  • 吓死猪队友 只用命令行登录Windows就问你怕不怕!
  • 从零开始学习Sencha Touch MVC应用之十四
  • 四 APPIUM GUI讲解(Windows版)(转)
  • net user使用
  • 如何在Ubuntu上使用Grafana监控Docker
  • 电脑快捷键
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • Apache Zeppelin在Apache Trafodion上的可视化
  • docker容器内的网络抓包
  • Java应用性能调优
  • leetcode388. Longest Absolute File Path
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • PHP变量
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • vue-router 实现分析
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 如何设计一个微型分布式架构?
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 小程序 setData 学问多
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 因为阿里,他们成了“杭漂”
  • # 数据结构
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • $jQuery 重写Alert样式方法
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (4)(4.6) Triducer
  • (Oracle)SQL优化技巧(一):分页查询
  • (TOJ2804)Even? Odd?
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (力扣)循环队列的实现与详解(C语言)
  • (三分钟)速览传统边缘检测算子
  • (循环依赖问题)学习spring的第九天
  • (转)大道至简,职场上做人做事做管理
  • (转载)深入super,看Python如何解决钻石继承难题
  • *p++,*(p++),*++p,(*p)++区别?
  • ./configure,make,make install的作用
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET Standard 的管理策略
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • .Net转前端开发-启航篇,如何定制博客园主题
  • @TableId注解详细介绍 mybaits 实体类主键注解
  • [ SNOI 2013 ] Quare