PHP是一种解释型语言,属于边编译边运行的那种。这种运行模式的优点是程序修改很方便,但是运行效率却很低下。
PHP缓存包括PHP编译缓存和PHP数据缓存两种。
PHP编译缓存针对这种情况做改进处理,使得PHP语言只要运行一次,就可以把程序的编译结果缓存起来。这样,接下来的每次运行都不需要再次编译了,这大大提高PHP运行速度。
PHP数据缓存运用于PHP实际开发之中针对数据处理进行缓存,主要两大方向为:针对数据库数据进行缓存和针对PHP模板数据进行缓存。也可以直接使用NoSQL。
一、技术特点
- 时间触发缓存
检查文件或数据是否存在并且时间戳小于设置的过期时间,如果文件修改的时间戳比当前时间戳减去过期时间戳大,那么就用缓存,否则更新缓存。
对于缓存文件需要设一个有效时间,在这个有效时间内,相同的访问才会先取缓存文件的内容,但是超过设定的缓存时间,就需要重新从数据库中获取数据, 并生产最新的缓存文件。
比如,将商城的首页就是设置2个小时更新一次。
- 内容触发缓存
当插入数据或更新数据时,强制更新PHP缓存机制。
例:一个人流量很大的商城,商品很多,商品表必然比较大,这表的压力也比较重;我们就可以对商品显示页进行页面缓存;当商家在后台修改这个商品的信息时,点击保存,我们同时就更新缓存文件;那么,买家访问这个商品信息时,实际上访问的是一个静态页面,而不需要再去访问数据库。
如果对商品页不缓存,那么每次访问一个商品就要去数据库查一次,如果有10万人在线浏览商品,那服务器压力就大了。
- 静态缓存
静态化,直接生成HTML或XML等文本文件,有更新的时候重生成一次,适合于不太变化的页面。
二、常用缓存
1.全页面静态化缓存
将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程。一般在CMS系统中比较常见。
<?php
/**
* ob_start()
* ob_clean()
* ob_end_clean()
* ob_flush()
* ob_end_flush()
* flush()
* ob_get_contents()
*
*/
ob_start(); //打开“输出控制缓冲”
/* some code 要运行的代码 */
$content = ob_get_contents(); //返回“输出缓冲区的内容”;
/* some code 使用file_put_contents()等函数将返回的数据写入HTML文件 */
ob_end_clean(); //清空“输出缓冲区”;
小例子:
#建立库
DROP DATABASE IF EXISTS `bigwebcore`;
CREATE DATABASE `bigwebcore` DEFAULT CHARSET utf8;
USE `bigwebcore`;
#建立新闻表
DROP TABLE IF EXISTS `news`;
CREATE TABLE `news`(
`id` int unsigned not null auto_increment,
`title` varchar(60) not null,
`content` varchar(255) not null,
`filename` varchar(60),
primary key(`id`)
)ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
INSERT INTO news(`title`,`content`) values('hello1','四川你好!');
INSERT INTO news(`title`,`content`) values('hello2','北京你好!');
<?php
header("Content-Type:text/html;charset=utf-8");
$db_host = 'localhost';
$db_port = 3306;
$db_name = 'bigwebcore';
$db_user = 'root';
$db_pwd = '123456';
$static = 'static';
$conn = mysql_connect($db_host,$db_user,$db_pwd) or die("数据库连接失败:".mysql_error());
mysql_query("set names utf8",$conn);
mysql_select_db($db_name,$conn);
if($_GET){
if($_GET['id']){
$id = intval($_GET['id']);
$html_filename = 'news-id-'.$id.'.html';
if(file_exists($html_filename) && filemtime($html_filename)+30 > time()){
echo file_get_contents($html_filename);
mysql_close();
exit;
}
$sql = "SELECT * FROM `news` WHERE id='{$id}'";
$result = mysql_query($sql,$conn);
ob_start();
if($row = mysql_fetch_array($result)){
echo "<meta charset=utf-8>";
echo "<table border='1' bordercolor='green' cellspacing='0' width='400px' height='200px'>";
echo "<tr><th>新闻详情</th></tr>";
echo "<tr><td>{$row['title']}</td></tr>";
echo "<tr><td>{$row['content']}</td></tr>";
echo "</table>";
}else{
echo "没有任何内容。";
}
mysql_free_result($result);
$html_content = ob_get_contents();
file_put_contents($static.'/'.$html_filename, $html_content);
//ob_end_flush();
}else{
echo "非法请求!";
}
}else{
$sql = "SELECT * FROM `news`";
$result = mysql_query($sql,$conn);
echo "<h1>新闻列表</h1>";
echo "<a href='#'>添加新闻</a><hr />";
echo "<table>";
echo "<tr><th>ID</th><th>标题</th><th>查看详情</th></tr>";
while($row = mysql_fetch_row($result)){
echo "<tr><td>{$row[0]}</td><td>{$row[1]}</td><td><a target='_blank' href='news.php?id={$row[0]}'>查看内容</a></td></tr>";
}
echo "</table>";
mysql_free_result($result);
}
mysql_close();
2.页面部分缓存
将页面中不常变动的部分进行静态化缓存,而经常变化的部分不缓存,最后组装在一起显示。
可以使用类似ob_get_contents()的方式实现,也可以利用类似ESI之类的页面片段缓存策略,使其用来做动态页面中相对静态的片段部分的缓存。
该缓存方式常用于商城中的商品页。
3.数据缓存
缓存数据的一种方式。
这里所说的数据缓存是指数据库查询PHP缓存机制,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果就直接从缓存表或文件中获得。
例一:商城中的某个商品信息,当用商品id去请求时,就会得出包括店铺信息、商品信息等数据,此时就可以将这些 数据缓存到一个php文件中,文件名包含商品id来建一个唯一标示;下一次有人想查看这个商品时,首先就直接调这个文件里面的信息,而不用再去数据库查询;缓存文件中缓存的就是一个php数组之类的。Ecmall商城系统里面就用了这种方式。
例二:多表关联的时候,把附表中的内容生成数组保存到主表的一个字段中,需要的时候数组分解一下,这样的好处是只读一个表,坏处就是两个数据同步会多不少步骤,数据库永远是瓶颈,用硬盘换速度,是这个的关键点。
4.查询缓存
其实这跟数据缓存是一个思路,就是根据查询语句来缓存;将查询得到的数据缓存在一个文件中,下次遇到相同的查询时,就直 接先从这个文件里面调数据,不会再去查数据库;但此处的缓存文件名可能就需要以查询语句为基点来建立唯一标示(md5($sql)等方式)。
5.内存缓存
使用redis,memcached等nosql数据库设置PHP缓存,通过缓存查询结果,来减少数据库的访问次数,从而提高网站的响应速度、 提高可扩展性。
memcache:
<?php
$memcache = new \Memcache; //创建一个memcache对象
$memcache->connect('localhost', 11211) or die ("Could not connect"); //连接Memcached服务器
$memcache->set('key', 'test'); //设置一个变量到内存中,名称是key 值是test
$get_value = $memcache->get('key'); //从内存中取出key的值
echo $get_value;
redis:
<?php
//连接本地的 Redis 服务
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
echo "Connection to server sucessfully";
//查看服务是否运行
echo "<br />";
echo "Server is running: " . $redis->ping();
//String字符串
echo "<br />";
$redis->set('test','test123');
echo $redis->get('test');
//List列表
echo "<br />";
$redis->lpush('zck','zck1');
$redis->lpush('zck','zck2');
$redis->lpush('zck','zck3');
$arList = $redis->lrange('zck',0,2);
print_r($arList);
//Keys
echo "<br />";
$arKeys = $redis->keys('*');
print_r($arKeys);
memcache、redis、MongoDB等NoSQL这儿只做了简单演示,实际使用会相对复杂得多。需要专门的专题或章节来讨论。
6.apache缓存模块
apache安装完以后,是不允许被cache的。
如果外接了cache或squid服务器要求进行web加速的话,就需要在htttpd.conf里进行设 置,前提是在安装apache的时候要激活mod_cache的模块。
安装apache时:./configure --enable-cache --enable-disk-cache --enable-mem-cache
7.PHP APC缓存
Php有一个APC缓存扩展,windows下面为php_apc.dll,需要先加载这个模块,然后是在php.ini里面进行配置:
[apc]
extension = php_apc.dll
apc.rfc1867 = on
upload_max_filesize = 100M
post_max_size = 100M
apc.max_file_size = 200M
upload_max_filesize = 1000M
post_max_size = 1000M
max_execution_time = 600 ; #每个PHP页面运行的最大时间值(秒),默认30秒
max_input_time = 600 ; #每个PHP页面接收数据所需的最大时间,默认60
memory_limit = 128M ; #每个PHP页面所吃掉的最大内存,默认8M
8.Opcode缓存
Zend引擎执行PHP流程:
- 将PHP代码转换为语言片段(Tokens)
- 将Tokens转换成简单而有意义的表达式
- 将表达式编译成Opocdes
- 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能返
所以,对于相同的php文件,第一次运行时可以缓存其Opcodes码,下次再执行这个页面时,直接会去找到缓存下的Opcodes码,直接执行最后一步,而不再需要中间的步骤了。
比较知名的是XCache、Turck MM Cache、PHP Accelerator等。