用户在每次访问PHP应用程序时,都会建立新的数据库连接并重新获取一次数据,再经过操作处理形成HTML等代码响应给用户。所以功能越强大的应用程序,执行时的开销就会越大。这是由于HTTP协议的无状态性造成的,对于每次页面的请求,都要重复地执行相同的操作,而不论数据是否被修改。但有些信息比如经常不变的,但是还是能变的信息。如果不想每次都重复执行相同的操作,就可以在第一次访问PHP应用程序时,将动态获取的HTML代码保存为静态页面,形成缓存文件。在以后每次请求该页面时,直接去读取缓存的数据,而不用每次都重复执行获取和处理操作带来的开销。这样,不仅可以加快页面的显示速度,而且我们在保存时通过指定下次更新的时间,也能达到缓存被动态更新的效果。比如需要60分钟更新一次,就可以根据记录的上次更新时间和当前时间比较,如果大于60分钟,重新读取数据库并更新缓存,否则还是直接读取缓存数据。所以,让Web应用程序运行得更高效,缓存技术是一种比较有效的解决方案。
16.8.1 在Smarty中控制缓存
Smarty缓存与前面介绍的Smarty编译是两个完全不同的机制,Smarty的编译功能在默认情况下是启用的,而缓存则必须由开发人员显示开启。编译的过程是将模板转换为PHP脚本,虽然Smarty模板在没被修改过的情况下,不会再重新执行转换过程,直接执行编译过的模板。但这个编译过的模板其实就是一个PHP脚本,只是减少了模板转换的开销,仍需要在逻辑层执行获取数据所需的动作,而这个动作执行开销是最大的。缓存则不仅将模板转换为PHP脚本执行,而且将模板内容转换成为静态页面,所以不仅减少了模板转换的开销,也没有了在逻辑层执行获取数据所需的开销。
1.建立缓存
如果需要使用缓存,首先要做的就是让缓存可用,这就要设置Smarty对象中的缓存属性,如下所示:
<DIV align=center>
<?php require('libs/Smarty.class.php'); //包含Smarty类库 $smarty = new Smarty; //创建Smarty类的对象 $smarty->caching = true; //启用缓存 $smarty->cache_dir = "./cache/"; //指定缓存文件保存的目录 $smarty->display('index.tpl') //也会把输出保存 ?> |
</DIV>
在上面PHP脚本中,通过设置Smarty对象中的$caching = true(或1)启用缓存。这样,当第一次调用Smarty对象中的display('index.tpl')方法时,不仅会把模板返回原来的状态(没缓存),也会把输出复制到由Smarty对象中的$cache_dir属性指定的目录下,保存为缓存文件。下次调用display('index.tpl')方法时,保存的缓存会被再用来代替原来的模板。在$chche_dir目录里的文件命名跟模板一致,尽管是用.php作为扩展名,但并不会被当做php代码来解析,所以不要去修改它。
2.处理缓存的生命周期
如果被缓存的页面永远都不更新,就会失去动态数据更新的效果。但对一些经常不变的,但还是需要改变的信息,我们可以通过指定一个更新时间,让缓存的页面在指定的时间内更新一次。缓存页面的更新时间(以秒为单位)是通过Smarty对象中$cache_lifetime属性指定的,默认的缓存时间为3600s。因此,如果希望修改此设置,就可以设置这个属性值。一旦指定的缓存时间失效,则缓存页面将会重新生成。如下所示:
<DIV align=center>
<?php require('libs/Smarty.class.php'); //包含Smarty类库 $smarty = new Smarty; //创建Smarty类的对象 $smarty->caching = 2; //启用缓存,在获取模板之前设置缓存生存时间 $smarty->cache_dir = "./cache/"; //指定缓存文件保存的目录 $smarty->cache_lifetime = 60*60*24*7; //设置缓存时间为1周 $smarty->display('index.tpl'); //也会把输出保存 ?> |
</DIV>
如果你想给某些模板设定它们自己的缓存生存时间,你可以在调用display()或fetch()函数之前,通过设置$caching = 2,然后设置$cache_lifetime为一个唯一值来实现。$caching必须因$cache_lifetime需要而设为true,值为-1时将强迫缓存永不过期,0值将导致缓存总是重新生成(仅有利于测试,一个更有效的使缓存无效的方法是设置$caching = false)。
大多数强大的Web应用程序功能都体现在其动态特性上,哪些文件你加了缓存,缓存时间多长都是很重要的。例如,你站点的首页内容不是经常更改,那么对首页缓存一个小时或是更长都可以得到很好效果。相反,几分钟就要更新一下信息的天气地图页面,用缓存就不好了。所以一方面考虑到性能提升,另一方面也要考虑到缓存页面的时间设置是否合理,要在这二者之间进行权衡。
16.8.2 每个页面多个缓存
例如,同一个新闻页面模板,是发布多篇新闻的通用界面。这样,同一个模板在使用时就会生成不同的页面实现。如果开启缓存,则通过同一个模板生成的多个实例都需要被缓存。Smarty实现这个问题比较容易,只要在调用display()方法时,通过在第二个可选参数中提供一个值,这个值是为每一个实例指定的一个唯一标识符,有几个不同的标识符就有几个缓存页面。如下所示:
<DIV align=center>
<?php require('libs/Smarty.class.php'); //包含Smarty类库 $smarty = new Smarty; //创建Smarty类的对象 $smarty->caching = 1; //启用缓存 $smarty->cache_dir = "./cache/"; //指定缓存文件保存的目录 $smarty->cache_lifetime = 60*60*24*7; //设置缓存时间为1周 /* $news=$db->getNews($_GET["newsid"]); //通过表单获取的新闻ID返回新闻对象 $smarty->assign("newsid", $news->getNewTitle()); //向模板中分配新闻标题 $smarty->assign("newsdt", $news->getNewDataTime()); //向模板中分配新闻时间 $smarty->assign("newsContent", $news->getNewContent); //向模板中分配新闻主体内容 */ $smarty->display('index.tpl', $_GET["newsid"]); //将新闻ID作为第二个参数提供 ?> |
</DIV>
在上例中,假设该脚本通过在GET方法中接收的新闻ID,从数据库中获取一篇新闻,并将新闻的标题、时间、内容通过assign()方法分配给指定的模板。在调用display()方法时,通过在第二个参数中提供的新闻ID,将这篇新闻缓存为单独的实例。采用这种方式,可以轻松地为每一篇新闻都缓存为一个唯一的实例。
16.8.3 为缓存实例消除处理开销
所谓的处理开销,是指在PHP脚本中动态获取数据和处理操作等的开销,如果启用了模板缓存就要消除这些处理开销。因为页面已经被缓存了,直接请求的是缓存文件,不需要再执行动态获取数据和处理操作了。如果禁用缓存,这些处理开销总是会发生的。解决的办法就是通过Smarty对象中的is_cached()方法,判断指定模板的缓存是否存在。使用的方式如下所示:
<DIV align=center>
<?php $smarty->caching = true; //开启缓存 if(!$smarty->is_cached("index.tpl")) { //判断模板文件imdex.tpl是否已经被缓存了 // 调用数据库,并对变量进行赋值 //消除了处理数据库的开销 } $smarty->display("index.tpl"); //直接寻找缓存的模板输出 ?> |
</DIV>
如果同一个模板有多个缓存实例的话,每个实例都要消除访问数据库和操作处理的开销,可以在is_cached()方法中通过第二个可选参数指定缓存号。如下所示:
<DIV align=center>
<?php require('libs/Smarty.class.php'); //包含Smarty类库 $smarty = new Smarty; //创建Smarty类的对象 $smarty->caching = 1; //启用缓存, $smarty->cache_dir = "./cache/"; //指定缓存文件保存的目录 $smarty->cache_lifetime = 60*60*24*7; //设置缓存时间为1周 if(!$smarty->is_cache('news.tpl', $_GET["newsid"])) { //判断news.tpl的某个实例是否被缓存 /* $news=$db->getNews($_GET["newsid"]); //获取的新闻ID返回新闻对象 $smarty->assign("newsid", $news->getNewTitle()); //向模板中分配新闻标题 $smarty->assign("newsdt", $news->getNewDataTime()); //向模板中分配新闻时间 $smarty->assign("newsContent", $news->getNewContent); //向模板中分配新闻主体内容 */ } $smarty->display('news.tpl', $_GET["newsid"]); //将新闻ID作为第二个参数提供 ?> |
</DIV>
在上例中is_cache()和display()两个方法,使用的参数是相同的,都是对同一个模板中的特定实例进行操作。
16.8.4 清除缓存
如果开启了模板缓存并指定了缓存时间,则页面在缓存的时间内输出结果不变。所以在程序开发过程中应该关闭缓存,因为程序员需要通过输出结果跟踪程序的运行过程,决定程序的下一步编写或用来调试程序等。但在项目开发结束时,在应用过程中就应当认真地考虑缓存,模板缓存大大提升了应用程序的性能。而用户在应用时,需要对网站内容进行管理,经常需要更新缓存,立即看到网站内容更改后的输出结果。
缓存的更新过程就是先清除缓存,再重新创建一次缓存文件。你可以用clear_all_cache()来清除所有缓存,或用clear_cache()来清除单个缓存文件。使用clear_cache()方法不仅清除指定模板的缓存,如果这个模板有多个缓存,你可以用第二个参数指定要清除缓存的缓存号。清除缓存的示例如下所示:
<DIV align=center>
<?php require('libs/Smarty.class.php'); $smarty = new Smarty(); $smarty->caching = true;
$smarty->clear_all_cache(); // 清除所有的缓存文件 $smarty->clear_cache("index.tpl"); // 清除某一模板的缓存 $smarty->clear_cache("index.tpl","CACHEID"); // 清除某一模板的多个缓存中指定缓存号的一个
$smarty->display('index.tpl'); ?> |
</DIV>
16.8.5 关闭局部缓存
对模板引擎来说,缓存是必不可少的,而局部缓存的作用也很明显,主要用于同一页中既有需要缓存的内容,又有不适宜缓存内容的情况,有选择的缓存某一部分内容或某一部分内容不被缓存。例如,在页面中如果需要显示用户的登录名称,很明显不能为每个用户都创建一个缓存页面,这就需要将显示用户名地方的缓存关闭,而页面的其他地方缓存。smarty也为我们提供了这种缓存控制能力,有以下三种处理方式。
Ø 使用{insert}使模板的一部分不被缓存。
Ø 可以使用$smarty->register_function($params, &$smarty)阻止插件从缓存中输出。
Ø 使用$smarty->register_block($params, &$smarty)使整篇页面中的某一块不被缓存。
如果使用register_function和register_block则能够方便地控制插件输出的缓冲能力。但一定要通过第三个参数控制是否缓存,默认是缓存的,需要我们显示设置为false。例如,“$smarty->register _block('name', 'smarty_block_name', false);”。而insert函数默认是不缓存的,并且这个属性不能修改。从这个意义上讲insert函数对缓存的控制能力似乎不如register_function和register_block强。最然这三种方法都可以很容易实现局部关闭缓存,但本节将介绍另一种最常用的方式,就是写成block插件的方式。步骤如下所示。
Ø 定义一件插件函数在block.cacheless.php文件中,并将其存放在smarty的plugins目录中,编写该文件的内容如下:
<DIV align=center>
<?php function smarty_block_cacheless($param, $content, &$smarty) { return $content; } ?> |
</DIV>
Ø 编写所用的模板cache.tpl文件:
<DIV align=center>
已经缓存的:{$smarty.now} <br> {cacheless} 没有缓存的:{$smarty.now} {/cacheless} |
</DIV>
Ø 编写程序及模板的示例程序testCacheLess.php:
<DIV align=center>
<?php include('Smarty.class.php'); $tpl = new Smarty; $tpl->caching=true; $tpl->cache_lifetime = 6; $tpl->display('cache.tpl'); ?> |
</DIV>
现在通过浏览器运行一下testCacheLess.php文件,发现是不起作用的,两行时间内容都被缓存了。这是因为block插件默认也是缓存的,所以还需要改写一下Smarty的源代码文件Smarty _Compiler.class.php,在该文件中查找到下面一条语句:
<DIV align=center>
$this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); |
</DIV>
可以直接将原句的最后一个参数改成false,即关闭默认的缓存。现在清除一下template_c目录里的编译文件,重新再运行testCacheLess.php文件即可。经过我们这几步的定义,以后只需要在模板定义中,不需要缓存的部分,例如,实时比分、广告、时间等,使用{cacheless}和{/cacheless}自定义的Smarty块标记,关闭缓存的内容即可。
转自:http://www.huachu.com.cn/read/readbookinfo.asp?sectionid=1000001806