文章教程

11.7Smarty的缓存处理

9/17/2020 9:49:37 PM 人评论 次浏览

11.7 Smarty的缓存处理

由于用户在每次访问PHP应用程序时,都会建立新的数据库连接并重新获取一次数据,再经过操作处理形成HTML等代码展示给用户,所以功能越强大的应用,执行时的开销就会越大。如果应用程序的数据是不经常变化的,这样显示是浪费资源的。如果不想每次都重复执行相同的操作,就可以在第一次访问PHP应用程序时,将动态获取的HTML代码保存为静态页面,形成缓存文件。在以后每次请求该页面时,直接去读取缓存的数据,而不用每次都重复执行获取和处理操作带来的开销。所以,让Web应用程序运行得更高效,缓存技术是一种比较有效的解决方案。

11.7.1 在Smarty中控制缓存

Smarty缓存与前面介绍的Smarty编译是两个完全不同的机制,Smarty的编译功能在默认情况下是启用的,而缓存则必须由开发人员开启。编译的过程是将模板转换为PHP脚本,虽然Smarty模板在没被修改过的情况下,不会再重新执行转换过程,直接执行编译过的模板。但这个编译过的模板还是一个动态的PHP页面,运行时还是需要PHP来解析的,如涉及数据库,还会去访问数据库,这也是开销最大的,所以它只是减少了模板转换的开销。缓存则不仅将模板转换为PHP脚本执行,而且将模板内容转换成为静态页面,所以不仅减少了模板转换的开销,也没有了在逻辑层执行获取数据所需的开销。

1.建立缓存

如果需要使用缓存,首先要做的就是让缓存可用,这就要设置Smarty对象中的缓存属性,如下所示。

  <?php
  require('libs/Smarty.class.php');               	//包含Smarty类库
  $smarty = new Smarty;				//创建Smarty类的对象
  $smarty->caching = true;			    	//启用缓存
  $smarty->cache_dir = "./cache/";                	//指定缓存文件保存的目录
  $smarty->display('index.tpl')                   	//也会把输出保存
  ?>

在上面PHP脚本中,通过设置Smarty对象中的$caching = true(或1)启用缓存。这样,当第一次调用Smarty对象中的display('index.tpl')方法时,不仅会把模板返回原来的状态(没缓存),也会把输出复制到由Smarty对象中的$cache_dir属性指定的目录下,保存为缓存文件。下次调用display('index.tpl')方法时,保存的缓存会被再用来代替原来的模板。

2.处理缓存的生命周期

如果被缓存的页面永远都不更新,就会失去动态数据更新的效果。但对一些经常需要改变的信息,可以通过指定一个更新时间,让缓存的页面在指定的时间内更新一次。缓存页面的更新时间(以s为单位)是通过Smarty对象中$cache_lifetime属性指定的,默认的缓存时间为3600s。如果希望修改此设置,就可以设置这个属性值。一旦指定的缓存时间失效,则缓存页面将会重新生成,如下所示。

  <?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');                  	//也会把输出保存
  ?>

如果想给某些模板设定它们自己的缓存生存时间,可以在调用display()或fetch()函数之前,通过设置$caching = 2,然后设置$cache_lifetime为一个唯一值来实现。$caching必须因$cache_lifetime需要而设为true,值为1时将强迫缓存永不过期,0值将导致缓存总是重新生成(建议仅测试使用,这里也可以设置$caching = false来使缓存无效)。

大多数强大的Web应用程序功能都体现在其动态特性上,哪些文件加了缓存,缓存时间多长都是很重要的。例如,站点的首页内容不是经常更改,那么对首页缓存一个小时或是更长都可以得到很好效果。相反,几分钟就要更新一下信息的天气地图页面,用缓存就不好了。所以一方面考虑到性能提升,另一方面也要考虑到缓存页面的时间设置是否合理,要在这二者之间进行权衡。

HBSI综合多用户商城同样使用了缓存机置,对于经常用到的信息,系统生成缓存文件到cache文件夹下,对于商品详细页面则是生成了静态页面,这些是使用商城自身的缓存机制完成的,而没有使用Smarty的缓存。如果想在商城使用Smarty强大的缓存功能,建议可缓存个别页面,而非整个商城系统,如会员注册、登录等页面,可为每个页面设定不同的缓存时间,可以将$ caching属性设置为2,然后结合$ cache_lifetime属性进行缓存。有些页面则不适合使用缓存,如商品搜索结果页面、使用Ajax调用的顶部页面等。

11.7.2 一个页面多个缓存

例如,同一个新闻页面模板,是发布多篇新闻的通用界面。这样,同一个模板在使用时就会生成不同的页面实现。如果开启缓存,则通过同一个模板生成的多个实例都需要被缓存。Smarty实现这个问题比较容易,只要在调用display()方法时,通过在第二个可选参数中提供一个值,这个值是为每一个实例指定的一个唯一标识符,有几个不同的标识符就有几个缓存页面,如下所示。

  <?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作为第二个参数提供
  ?>

在上例中,假设该脚本通过在GET方法中接收的新闻ID,从数据库中获取一篇新闻,并将新闻的标题、时间、内容通过assign()方法分配给指定的模板。在调用display()方法时,通过在第二个参数中提供的新闻ID,将这篇新闻缓存为单独的实例。采用这种方式,可以轻松地为每一篇新闻都缓存为一个唯一的实例。

11.7.3 为缓存实例消除处理开销

所谓的处理开销,是指在PHP脚本中动态获取数据和处理操作等的开销,如果启用了模板缓存就要消除这些处理开销。因为页面已经被缓存了,直接请求的是缓存文件,不需要再执行动态获取数据和处理操作了。如果禁用缓存,这些处理开销总是会发生的。解决的办法就是通过Smarty对象中的is_cached()方法,判断指定模板的缓存是否存在。使用的方式如下所示。

  <?php
  $smarty->caching = true;                    	//开启缓存
  if(!$smarty->is_cached("index.tpl")) {
  //判断模板文件imdex.tpl是否已经被缓存了
  //调用数据库,并对变量进行赋值          		//消除了处理数据库的开销
  }
  $smarty->display("index.tpl");            		//直接寻找缓存的模板输出
  ?>

如果同一个模板有多个缓存实例,每个实例都要消除访问数据库和操作处理的开销,可以在is_cached()方法中通过第二个可选参数指定缓存号,如下所示。

  <?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_cached('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作为第二个参数提供
  ?>

在上例中is_cache()和display()两个方法,使用的参数是相同的,都是对同一个模板中的特定实例进行操作。

11.7.4 清除缓存

如果开启了模板缓存并指定了缓存时间,则页面在缓存的时间内输出结果不变。所以在程序开发过程中应该关闭缓存,因为程序员需要通过输出结果跟踪程序的运行过程,决定程序的下一步编写或用来调试程序等。但在项目开发结束时,在应用过程中就应当认真地考虑缓存,模板缓存大大提升了应用程序的性能。而用户在应用时,需要对网站内容进行管理,经常需要更新缓存,立即看到网站内容更改后的输出结果。

缓存的更新过程就是先清除缓存,再重新创建一次缓存文件。可以用clear_all_cache()来清除所有缓存,或用clear_cache()来清除单个缓存文件。使用clear_cache()方法不仅清除指定模板的缓存,如果这个模板有多个缓存,可以用第二个参数指定要清除缓存的缓存号。清除缓存的示例如下所示。

  <?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');

11.7.5 关闭局部缓存

对模板引擎来说,缓存是必不可少的,而局部缓存的作用也很明显,主要用于同一页中既有需要缓存的内容,又有不适宜缓存内容的情况,有选择地缓存某一部分内容或某一部分内容不被缓存。例如,在页面中如果需要显示用户的登录名称,很明显不能为每个用户都创建一个缓存页面,这就需要将显示用户名地方的缓存关闭,而页面的其他地方缓存。Smarty也提供了这种缓存控制能力,有以下三种处理方式。

(1)使用{insert}使模板的一部分不被缓存。

(2)可以使用$smarty->register_function($params, &$smarty)阻止插件从缓存中输出。

(3)使用$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目录中,内容如下。

  <?php
  function smarty_block_cacheless($param, $content, &$smarty) {
  return $content;
  }
  ?>

编写所用的模板cache.tpl文件:

  已经缓存的:{$smarty.now}
  <br>
  {cacheless}
  没有缓存的:{$smarty.now}
  {/cacheless}

编写程序及模板的示例程序testCacheLess.php:

  <?php
  include('Smarty.class.php');
  $tpl = new Smarty;
  $tpl->caching=true;
  $tpl->cache_lifetime = 6;
  $tpl->display('cache.tpl');
  ?>

现在通过浏览器运行一下testCacheLess.php文件,发现是不起作用的,两行时间内容都被缓存了。这是因为block插件默认也是缓存的,所以还需要改写一下Smarty的源代码文件Smarty _Compiler.class.php,在该文件中查找到下面一条语句:

  $this->_plugins['block'][$tag_command] =array($plugin_func, null, null,
  null, true);

可以直接将原句的最后一个参数改成false,即关闭默认的缓存。现在清除一下template_c目录里的编译文件,重新再运行testCacheLess.php文件即可。经过这几步的定义,以后只需要在模板定义中不需要缓存的部分,例如,实时比分、广告、时间等,使用{cacheless}和{/cacheless}自定义的Smarty块标记,关闭缓存的内容即可。

教程类别