在典型的 Web 环境中,相同的内容会反复展示给访问您网站的每个人。缓存可以通过将代码生成的部分或全部信息存储在文件中并在需要时返回,从而加快这一过程。实现缓存的方法有多种,但本教程仅涉及函数缓存。好消息是,在 Joomla! 中,这非常简单
使用性能分析器 (Profiler)
当使用缓存函数时,您需要确保缓存的函数确实比不使用缓存的函数更快。我们将使用 Joomla! 的性能分析器 (JProfiler
) 来测试这一点。
<?php // 创建性能分析器对象。 $profiler = new JProfiler(); // 执行一些操作。 echo $profiler->mark('执行操作耗时'); ?>
这可能会输出类似的内容:
0.001 执行操作耗时
如果您反复运行相同的代码,可能会看到数字有一些微小的差异。这可能是由于系统上运行的其他进程造成的。
要测试的函数
我们将创建一个实际上不执行任何操作的小型组件,但允许我们计算执行函数所需的时间。
首先创建组件的文件:/components/com_testcache/testcache.php
在里面,我们创建一个包含一个方法的类。
<?php // 禁止直接访问。 defined('_JEXEC') or die('Restricted access'); class TestClass { function testMethod() { // 获取全局数据库对象的引用。 $db = JFactory::getDBO(); // 执行相同的数据库查询 250 次。 for ($i = 0; $i < 250; $i++) { $db->setQuery('SELECT * FROM #__content'); $rows = $db->loadObjectList(); } return $rows; } } // 运行测试。 $rows = TestClass::testMethod(); ?>
我们将数据库调用循环 250 次,这样函数会变得非常慢。这样我们在使用缓存时就能看到巨大的差异。当然,在实际代码中我们绝不会做这样的事情。
缓存函数
首先,确保在全局配置 (Global Configuration)中将扩展缓存 (Extension Cache) 设置为 是 (Yes)
。
我们使用 JFactory
类获取缓存的引用:
<?php $cache = JFactory::getCache(); ?>
如果您希望您的组件使用缓存,即使在全局配置中缓存被关闭,您也可以自行设置:
<?php $cache->setCaching(1); // 1 表示开启 ?>
接下来我们调用我们的方法:
<?php $rows = $cache->call(array('TestClass', 'testMethod')); ?>
如果我们想缓存一个不在类中的函数,则不需要使用数组:
<?php $rows = $cache->call('testFunction'); ?>
在测试代码时,我们可以使用以下方法清理缓存:
<?php $cache->cleanCache(); // 清理所有缓存 ?>
这将删除 /cache
文件夹中的所有文件。
整合测试代码
为了比较速度,我们现在将调用测试方法两次;一次使用“普通”方式,一次使用缓存。我们将把两个调用包装在性能分析器对象中,以便看到差异。
<?php class TestClass { function testMethod() { // 获取全局数据库对象的引用。 $db = JFactory::getDBO(); // 执行相同的数据库查询 250 次。 for ($i = 0; $i < 250; $i++) { $db->setQuery('SELECT * FROM #__content'); $rows = $db->loadObjectList(); } return $rows; } } // 获取全局缓存对象的引用。 $cache = JFactory::getCache(); // 不使用缓存运行测试。 $profiler = new JProfiler(); $rows = TestClass::testMethod(); echo $profiler->mark(' 不使用缓存'); // 使用缓存运行测试。 $profiler = new JProfiler(); $rows = $cache->call(array('TestClass', 'testMethod')); echo $profiler->mark(' 使用缓存'); ?>
现在通过 index.php?option=com_testcache
执行该组件。
第一次执行时,您可能会看到类似以下的内容:
2.093 不使用缓存 2.160 使用缓存
第二个(使用缓存)稍微慢一点,因为返回的数据需要写入文件。
现在在浏览器中重新加载页面:
2.073 不使用缓存 0.008 使用缓存
将这些数字乘以您的网站在 900 秒内(Joomla! 默认存储缓存数据的时间)获得的点击量。效果不错吧?
再次重新加载页面几次,您会看到数字有微小的差异。
带参数的函数
在我们的示例中,函数反复返回相同的数据。然而,通常您会编写接受一些参数并计算不同数据的函数。这同样简单:只需将参数添加到调用中即可。
我们将用一个可变的表名扩展我们的示例。
<?php class TestClass { function testMethod($table) { // 获取全局数据库对象的引用。 $db = JFactory::getDBO(); // 执行相同的数据库查询 250 次。 for ($i = 0; $i < 250; $i++) { $db->setQuery("SELECT * FROM #__$table"); $rows = $db->loadObjectList(); } return $rows; } } // 确定要查询的数据库表。 $table = JFactory::getApplication()->input->getString('table', 'content'); // 默认为 'content' // 获取全局缓存对象的引用。 $cache = JFactory::getCache(); // 不使用缓存运行测试。 $profiler = new JProfiler(); $rows = TestClass::testMethod($table); echo $profiler->mark(' 不使用缓存'); // 使用缓存运行测试。 $profiler = new JProfiler(); $rows = $cache->call(array('TestClass', 'testMethod'), $table); echo $profiler->mark(' 使用缓存'); ?>
尝试使用不同的表名加载页面:
index.php?option=com_testcache&table=content
index.php?option=com_testcache&table=users
index.php?option=com_testcache&table=menu
您会看到,如果页面是第一次加载,使用缓存的方法会稍慢一些,但重新加载时,使用缓存会更快。
调用对象实例的方法
如果您需要调用对象实例的方法 ($something->somefunction
与此示例之前使用的 something::somefunction
不同),您可以这样使用:
$something = $this->SomeOtherfunction; $mySomething = $cache->call(array($something, 'somefunction'), 'par1', 'par2', 'par3');
您可以像上面的例子一样,用逗号分隔传递多个参数。
何时使用缓存?
我们的示例使用了一个非常慢的函数,它查询数据库 250 次。很容易看出在这里使用缓存如何能真正加快速度。然而,使用缓存并不总是更快。尝试移除示例中的循环,您就会明白。
这就是为什么使用性能分析器来查看您是否能从缓存中受益非常重要。当然,这也取决于您的代码所运行的系统。如果系统拥有庞大的数据库,缓存可能会更快。
在规划代码时也要牢记缓存也很重要。一个函数只有在对于给定的一组参数每次都返回相同数据时才能被缓存。当然,缓存不能替代高效的编码。;)
缓存 $this->function
的问题
当缓存对 $this
的函数调用时,请注意缓存函数会考虑所有对象变量来确定是否需要刷新缓存。如果对象包含时间戳、会话 ID 或每次都会变化的类似内容,那么缓存实际上会被自动禁用。
解决此问题的一种方法是构建您自己的单例模式 (Singleton) 来存储需要共享的信息,并使用静态调用代替。
评论 (0)