深入解析PHP的Yii框架中的缓存功能

数据缓存是指将一些 PHP 变量存储到缓存中,使用时再从缓存中取回。它也是更高级缓存特性的基础,例如查询缓存和内容缓存。

如下代码是一个典型的数据缓存使用模式。其中 $cache 指向缓存组件:

// 尝试从缓存中取回 $data
$data = $cache->get($key);

if ($data === false) {

  // $data 在缓存中没有找到,则重新计算它的值

  // 将 $data 存放到缓存供下次使用
  $cache->set($key, $data);
}

// 这儿 $data 可以使用了。

缓存组件

数据缓存需要缓存组件提供支持,它代表各种缓存存储器,例如内存,文件,数据库。

缓存组件通常注册为应用程序组件,这样它们就可以在全局进行配置与访问。如下代码演示了如何配置应用程序组件 cache 使用两个 memcached 服务器:

'components' => [
  'cache' => [
    'class' => 'yii\caching\MemCache',
    'servers' => [
      [
        'host' => 'server1',
        'port' => 11211,
        'weight' => 100,
      ],
      [
        'host' => 'server2',
        'port' => 11211,
        'weight' => 50,
      ],
    ],
  ],
],

然后就可以通过 Yii::$app->cache 访问上面的缓存组件了。

由于所有缓存组件都支持同样的一系列 API ,并不需要修改使用缓存的业务代码就能直接替换为其他底层缓存组件,只需在应用配置中重新配置一下就可以。例如,你可以将上述配置修改为使用 yii\caching\ApcCache:

'components' => [
  'cache' => [
    'class' => 'yii\caching\ApcCache',
  ],
],

Tip: 你可以注册多个缓存组件,很多依赖缓存的类默认调用名为 cache 的组件(例如 yii\web\UrlManager)。
支持的缓存存储器

Yii 支持一系列缓存存储器,概况如下:

  • yii\caching\ApcCache:使用 PHP APC 扩展。这个选项可以认为是集中式应用程序环境中(例如:单一服务器,没有独立的负载均衡器等)最快的缓存方案。
  • yii\caching\DbCache:使用一个数据库的表存储缓存数据。要使用这个缓存,你必须创建一个与 yii\caching\DbCache::cacheTable 对应的表。
  • yii\caching\DummyCache: 仅作为一个缓存占位符,不实现任何真正的缓存功能。这个组件的目的是为了简化那些需要查询缓存有效性的代码。例如,在开发中如果服务器没有实际的缓存支持,用它配置一个缓存组件。一个真正的缓存服务启用后,可以再切换为使用相应的缓存组件。两种条件下你都可以使用同样的代码 Yii::$app->cache->get($key) 尝试从缓存中取回数据而不用担心 Yii::$app->cache 可能是 null。
  • yii\caching\FileCache:使用标准文件存储缓存数据。这个特别适用于缓存大块数据,例如一个整页的内容。
  • yii\caching\MemCache:使用 PHP memcache 和 memcached 扩展。这个选项被看作分布式应用环境中(例如:多台服务器,有负载均衡等)最快的缓存方案。
  • yii\redis\Cache:实现了一个基于 Redis 键值对存储器的缓存组件(需要 redis 2.6.12 及以上版本的支持 )。
  • yii\caching\WinCache:使用 PHP WinCache(另可参考)扩展.
  • yii\caching\XCache:使用 PHP XCache扩展。
  • yii\caching\ZendDataCache:使用 Zend Data Cache 作为底层缓存媒介。
  • Tip: 你可以在同一个应用程序中使用不同的缓存存储器。一个常见的策略是使用基于内存的缓存存储器存储小而常用的数据(例如:统计数据),使用基于文件或数据库的缓存存储器存储大而不太常用的数据(例如:网页内容)。

缓存 API

所有缓存组件都有同样的基类 yii\caching\Cache ,因此都支持如下 API:

  • yii\caching\Cache::get():通过一个指定的键(key)从缓存中取回一项数据。如果该项数据不存在于缓存中或者已经过期/失效,则返回值 false。
  • yii\caching\Cache::set():将一项数据指定一个键,存放到缓存中。
  • yii\caching\Cache::add():如果缓存中未找到该键,则将指定数据存放到缓存中。
  • yii\caching\Cache::mget():通过指定的多个键从缓存中取回多项数据。
  • yii\caching\Cache::mset():将多项数据存储到缓存中,每项数据对应一个键。
  • yii\caching\Cache::madd():将多项数据存储到缓存中,每项数据对应一个键。如果某个键已经存在于缓存中,则该项数据会被跳过。
  • yii\caching\Cache::exists():返回一个值,指明某个键是否存在于缓存中。
  • yii\caching\Cache::delete():通过一个键,删除缓存中对应的值。
  • yii\caching\Cache::flush():删除缓存中的所有数据。
  • 有些缓存存储器如 MemCache,APC 支持以批量模式取回缓存值,这样可以节省取回缓存数据的开支。 yii\caching\Cache::mget() 和 yii\caching\Cache::madd() API提供对该特性的支持。如果底层缓存存储器不支持该特性,Yii 也会模拟实现。

由于 yii\caching\Cache 实现了 PHP ArrayAccess 接口,缓存组件也可以像数组那样使用,下面是几个例子:

$cache['var1'] = $value1; // 等价于: $cache->set('var1', $value1);
$value2 = $cache['var2']; // 等价于: $value2 = $cache->get('var2');

缓存键

存储在缓存中的每项数据都通过键作唯一识别。当你在缓存中存储一项数据时,必须为它指定一个键,稍后从缓存中取回数据时,也需要提供相应的键。

你可以使用一个字符串或者任意值作为一个缓存键。当键不是一个字符串时,它将会自动被序列化为一个字符串。

定义一个缓存键常见的一个策略就是在一个数组中包含所有的决定性因素。例如,yii\db\Schema 使用如下键存储一个数据表的结构信息。

[
  __CLASS__,       // 结构类名
  $this->db->dsn,     // 数据源名称
  $this->db->username,  // 数据库登录用户名
  $name,         // 表名
];

如你所见,该键包含了可唯一指定一个数据库表所需的所有必要信息。

当同一个缓存存储器被用于多个不同的应用时,应该为每个应用指定一个唯一的缓存键前缀以避免缓存键冲突。可以通过配置 yii\caching\Cache::keyPrefix 属性实现。例如,在应用配置中可以编写如下代码:

'components' => [
  'cache' => [
    'class' => 'yii\caching\ApcCache',
    'keyPrefix' => 'myapp',    // 唯一键前缀
  ],
],

为了确保互通性,此处只能使用字母和数字。

缓存过期

默认情况下,缓存中的数据会永久存留,除非它被某些缓存策略强制移除(例如:缓存空间已满,最老的数据会被移除)。要改变此特性,你可以在调用 yii\caching\Cache::set() 存储一项数据时提供一个过期时间参数。该参数代表这项数据在缓存中可保持有效多少秒。当你调用 yii\caching\Cache::get() 取回数据时,如果它已经过了超时时间,该方法将返回 false,表明在缓存中找不到这项数据。例如:

// 将数据在缓存中保留 45 秒
$cache->set($key, $data, 45);

sleep(50);

$data = $cache->get($key);
if ($data === false) {
  // $data 已过期,或者在缓存中找不到
}

缓存依赖

除了超时设置,缓存数据还可能受到缓存依赖的影响而失效。例如,yii\caching\FileDependency 代表对一个文件修改时间的依赖。这个依赖条件发生变化也就意味着相应的文件已经被修改。因此,缓存中任何过期的文件内容都应该被置为失效状态,对 yii\caching\Cache::get() 的调用都应该返回 false。

缓存依赖用 yii\caching\Dependency 的派生类所表示。当调用 yii\caching\Cache::set() 在缓存中存储一项数据时,可以同时传递一个关联的缓存依赖对象。例如:

// 创建一个对 example.txt 文件修改时间的缓存依赖
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);

// 缓存数据将在30秒后超时
// 如果 example.txt 被修改,它也可能被更早地置为失效状态。
$cache->set($key, $data, 30, $dependency);

// 缓存会检查数据是否已超时。
// 它还会检查关联的依赖是否已变化。
// 符合任何一个条件时都会返回 false。
$data = $cache->get($key);

下面是可用的缓存依赖的概况:

  • yii\caching\ChainedDependency:如果依赖链上任何一个依赖产生变化,则依赖改变。
  • yii\caching\DbDependency:如果指定 SQL 语句的查询结果发生了变化,则依赖改变。
  • yii\caching\ExpressionDependency:如果指定的 PHP 表达式执行结果发生变化,则依赖改变。
  • yii\caching\FileDependency:如果文件的最后修改时间发生变化,则依赖改变。
  • yii\caching\GroupDependency:将一项缓存数据标记到一个组名,你可以通过调用 yii\caching\GroupDependency::invalidate() 一次性将相同组名的缓存全部置为失效状态。

查询缓存

查询缓存是一个建立在数据缓存之上的特殊缓存特性。它用于缓存数据库查询的结果。

查询缓存需要一个 yii\db\Connection 和一个有效的 cache 应用组件。查询缓存的基本用法如下,假设 $db 是一个 yii\db\Connection 实例:

$duration = 60;   // 缓存查询结果60秒
$dependency = ...; // 可选的缓存依赖

$db->beginCache($duration, $dependency);

// ...这儿执行数据库查询...

$db->endCache();

如你所见,beginCache() 和 endCache() 中间的任何查询结果都会被缓存起来。如果缓存中找到了同样查询的结果,则查询会被跳过,直接从缓存中提取结果。

查询缓存可以用于 ActiveRecord 和 DAO。

Info: 有些 DBMS (例如:MySQL)也支持数据库服务器端的查询缓存。你可以选择使用任一查询缓存机制。上文所述的查询缓存的好处在于你可以指定更灵活的缓存依赖因此可能更加高效。
配置

查询缓存有两个通过 yii\db\Connection 设置的配置项:

yii\db\Connection::queryCacheDuration: 查询结果在缓存中的有效期,以秒表示。如果在调用 yii\db\Connection::beginCache() 时传递了一个显式的时值参数,则配置中的有效期时值会被覆盖。
yii\db\Connection::queryCache: 缓存应用组件的 ID。默认为 'cache'。只有在设置了一个有效的缓存应用组件时,查询缓存才会有效。
限制条件

当查询结果中含有资源句柄时,查询缓存无法使用。例如,在有些 DBMS 中使用了 BLOB 列的时候,缓存结果会为该数据列返回一个资源句柄。

有些缓存存储器有大小限制。例如,memcache 限制每条数据最大为 1MB。因此,如果查询结果的大小超出了该限制,则会导致缓存失败。

片段缓存

片段缓存指的是缓存页面内容中的某个片段。例如,一个页面显示了逐年销售额的摘要表格,可以把表格缓存下来,以消除每次请求都要重新生成表格的耗时。片段缓存是基于数据缓存实现的。

在视图中使用以下结构启用片段缓存:

if ($this->beginCache($id)) {

  // ... 在此生成内容 ...

  $this->endCache();
}

调用 yii\base\View::beginCache() 和 yii\base\View::endCache() 方法包裹内容生成逻辑。如果缓存中存在该内容,yii\base\View::beginCache() 方法将渲染内容并返回 false,因此将跳过内容生成逻辑。否则,内容生成逻辑被执行,一直执行到 yii\base\View::endCache() 时,生成的内容将被捕获并存储在缓存中。

和[数据缓存]一样,每个片段缓存也需要全局唯一的 $id 标记。

缓存选项

如果要为片段缓存指定额外配置项,请通过向 yii\base\View::beginCache() 方法第二个参数传递配置数组。在框架内部,该数组将被用来配置一个 yii\widget\FragmentCache 小部件用以实现片段缓存功能。

过期时间(duration)

或许片段缓存中最常用的一个配置选项就是 yii\widgets\FragmentCache::duration 了。它指定了内容被缓存的秒数。以下代码缓存内容最多一小时:

if ($this->beginCache($id, ['duration' => 3600])) {

  // ... 在此生成内容 ...

  $this->endCache();
}

如果该选项未设置,则默认为 0,永不过期。

依赖

和[数据缓存]一样,片段缓存的内容一样可以设置缓存依赖。例如一段被缓存的文章,是否重新缓存取决于它是否被修改过。

通过设置 yii\widgets\FragmentCache::dependency 选项来指定依赖,该选项的值可以是一个 yii\caching\Dependency 类的派生类,也可以是创建缓存对象的配置数组。以下代码指定了一个片段缓存,它依赖于 update_at 字段是否被更改过的。

$dependency = [
  'class' => 'yii\caching\DbDependency',
  'sql' => 'SELECT MAX(updated_at) FROM post',
];

if ($this->beginCache($id, ['dependency' => $dependency])) {

  // ... 在此生成内容 ...

  $this->endCache();
}

变化

缓存的内容可能需要根据一些参数的更改而变化。例如一个 Web 应用支持多语言,同一段视图代码也许需要生成多个语言的内容。因此可以设置缓存根据应用当前语言而变化。

通过设置 yii\widgets\FragmentCache::variations 选项来指定变化,该选项的值应该是一个标量,每个标量代表不同的变化系数。例如设置缓存根据当前语言而变化可以用以下代码:

if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) {

  // ... 在此生成内容 ...

  $this->endCache();
}

开关

有时你可能只想在特定条件下开启片段缓存。例如,一个显示表单的页面,可能只需要在初次请求时缓存表单(通过 GET 请求)。随后请求所显示(通过 POST 请求)的表单不该使用缓存,因为此时表单中可能包含用户输入内容。鉴于此种情况,可以使用 yii\widgets\FragmentCache::enabled 选项来指定缓存开关,如下所示:

if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {

  // ... 在此生成内容 ...

  $this->endCache();
}

缓存嵌套

片段缓存可以被嵌套使用。一个片段缓存可以被另一个包裹。例如,评论被缓存在里层,同时整个评论的片段又被缓存在外层的文章中。以下代码展示了片段缓存的嵌套使用:

if ($this->beginCache($id1)) {

  // ...在此生成内容...

  if ($this->beginCache($id2, $options2)) {

    // ...在此生成内容...

    $this->endCache();
  }

  // ...在此生成内容...

  $this->endCache();
}

可以为嵌套的缓存设置不同的配置项。例如,内层缓存和外层缓存使用不同的过期时间。甚至当外层缓存的数据过期失效了,内层缓存仍然可能提供有效的片段缓存数据。但是,反之则不然。如果外层片段缓存没有过期而被视为有效,此时即使内层片段缓存已经失效,它也将继续提供同样的缓存副本。因此,你必须谨慎处理缓存嵌套中的过期时间和依赖,否则外层的片段很有可能返回的是不符合你预期的失效数据。

译注:外层的失效时间应该短于内层,外层的依赖条件应该低于内层,以确保最小的片段,返回的是最新的数据。
动态内容

使用片段缓存时,可能会遇到一大段较为静态的内容中有少许动态内容的情况。例如,一个显示着菜单栏和当前用户名的页面头部。还有一种可能是缓存的内容可能包含每次请求都需要执行的 PHP 代码(例如注册资源包的代码)。这两个问题都可以使用动态内容功能解决。

动态内容的意思是这部分输出的内容不该被缓存,即便是它被包裹在片段缓存中。为了使内容保持动态,每次请求都执行 PHP 代码生成,即使这些代码已经被缓存了。

可以在片段缓存中调用 yii\base\View::renderDynamic() 去插入动态内容,如下所示:

if ($this->beginCache($id1)) {

  // ...在此生成内容...

  echo $this->renderDynamic('return Yii::$app->user->identity->name;');

  // ...在此生成内容...

  $this->endCache();
}

yii\base\View::renderDynamic() 方法接受一段 PHP 代码作为参数。代码的返回值被看作是动态内容。这段代码将在每次请求时都执行,无论其外层的片段缓存是否被存储。

(0)

相关推荐

  • Yii开启片段缓存的方法

    本文实例讲述了Yii开启片段缓存的方法.分享给大家供大家参考,具体如下: 1.main.php文件中的components中添加: cache'=>array( 'class'=>'system.caching.CFileCache', ), 2.在view中哪里需要缓存就添加这句话 <?php if($this->beginCache('aaa', array( 'duration'=>3360, 'varyByParam'=>array('page'), 'depe

  • Yii配置与使用memcached缓存的方法

    本文实例讲述了Yii配置与使用memcached缓存的方法.分享给大家供大家参考,具体如下: 1. 下载memcached软件包,解压,把memcached.exe 放到随意一个地方,比如:d:/memcached/ 下. 2. 开始->运行->输入cmd,命令行打开memcached.exe,所在文件夹,输入:memcached.exe -d install  安装 3. 输入memcached.exe -d start 启动 4. 中加入 extension=php_memcache.dl

  • 浅析Yii2缓存的使用

    一个好的框架是肯定离不开缓存的使用,相反,一个没有缓存的框架也肯定不是一个好框架,好像是一个意思,不管了,我们先来看看yii2中是如何使用缓存的吧. 又是到我们第一步操作的时候了,我们先来配置组件. 方便起见,我们的缓存组件配置在common\config\main.php文件,先来简单配置下文件缓存 'components' => [ 'cache' => [ 'class' => 'yii\caching\FileCache', 'cachePath' => '@runtime

  • Yii数据库缓存实例分析

    本文实例讲述了Yii数据库缓存用法.分享给大家供大家参考,具体如下: yii  操作数据库缓存: 1.在main.php主文件中添加 'dbcache'=>array( 'class'=>'system.caching.CDbCache', //数据库缓存,注意你自己的路径问题 ), 2.设置数据库缓存 Yii::app()->cache->set($key,$value,$outtime); //$key 唯一主键,$value 对应主键的值(可以是数组), $outtime 过

  • Yii清理缓存的方法

    本文实例讲述了Yii清理缓存的方法.分享给大家供大家参考,具体如下: html: 复制代码 代码如下: <button onclick="clearCache()">ClearCache</button> js: function clearCache() { $.get('../eng/index.php?r=site/clear&'+new Date().getTime(),function(){ alert('Clear eng cache ok.

  • Yii2 assets清除缓存的方法

    本文实例讲述了Yii2 assets清除缓存的方法.分享给大家供大家参考,具体如下: use vendor\myVendorName\myPackageName\assets\AppAsset; AppAsset::register($this); 在配置文件中添加: 'components' => [ 'assetManager' => [ 'linkAssets' => true, ], ] 刷新后就可以清除缓存 更多关于Yii相关内容感兴趣的读者可查看本站专题:<Yii框架入

  • Yii 2.0如何使用页面缓存方法示例

    前言 本文主要给大家介绍的是关于Yii2.0如何使用页面缓存的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍. 起初使用页面缓存,发现使用于含有参数的方法存在弊端,只能缓存第一次的页面,导致后面所有不同参数的页面均显示第一次缓存页面:没有生成一个参数页面一个缓存:于是,进行了重写页面缓存. 示例代码 <?php namespace common\lib; use Yii; use yii\caching\Cache; use yii\di\Instance; use yii\web\

  • 简介PHP的Yii框架中缓存的一些高级用法

    页面缓存 页面缓存指的是在服务器端缓存整个页面的内容.随后当同一个页面被请求时,内容将从缓存中取出,而不是重新生成. 页面缓存由 yii\filters\PageCache 类提供支持,该类是一个过滤器.它可以像这样在控制器类中使用: public function behaviors() { return [ [ 'class' => 'yii\filters\PageCache', 'only' => ['index'], 'duration' => 60, 'variations'

  • YII框架中使用memcache的方法详解

    本文实例讲述了YII框架中使用memcache的方法.分享给大家供大家参考,具体如下: yii中可以很方便的使用memcache 一.配置 在main.php的components中加入cache配置 array( 'components'=>array( 'cache'=>array( 'class'=>'CMemCache', 'servers'=>array( array( 'host'=>'server1', 'port'=>11211, 'weight'=&g

  • Yii框架中memcache用法实例

    本文实例讲述了Yii框架中memcache用法.分享给大家供大家参考.具体分析如下: 在现在的公司用的是YII的框架,接触到的东西也比较多,可以学到的东西也比较多,在以前的公司没有接触过memcache,只是听过,但是从来没有真正用过.现在终于有机会使用一下了,就以我做的项目为例吧! 我做的项目是一个手机排行榜,但是排行榜每隔15分钟刷新一次啊,排行榜有一个前三名,可能前15分钟这三个人是前三名,也许下一个15分钟又是别人前三名了,产品要求,这些人中只要是前三名的都要发奖品,思考了好久,最终决定

  • YII Framework框架教程之缓存用法详解

    本文实例讲述了YII Framework框架缓存用法.分享给大家供大家参考,具体如下: 缓存的产生原因众所周知.于是YII作为一个高效,好用的框架,不能不支持缓存.所以YII对各种流行的缓存都提供了接口,你可以根据你的需要使用不同的缓存. 1.YII中的缓存介绍 YII中的缓存是通过组件方式定义的,具体在如下目录 /yii_dev/yii/framework/caching# tree . ├── CApcCache.php ├── CCache.php ├── CDbCache.php ├──

  • yii2缓存Caching基本用法示例

    本文实例讲述了yii2缓存Caching基本用法.分享给大家供大家参考,具体如下: 在yii的配置文件中添加: 'cache' => [ 'class' => 'yii\caching\ApcCache', ], 缓存的使用: <?php $key = 'cacheKey'; //读取缓存 $data = Yii::$app->cache->get($key); //判断缓存是否存在,如果不存就生成缓存 if ($data === false) { $cache->se

随机推荐