# 緩存
- [配置信息](#configuration)
- [驅動前提條件](#driver-prerequisites)
- [緩存的使用](#cache-usage)
- [獲取一個緩存實例](#obtaining-a-cache-instance)
- [從緩存中獲取項目](#retrieving-items-from-the-cache)
- [存放項目到緩存中](#storing-items-in-the-cache)
- [刪除緩存中的項目](#removing-items-from-the-cache)
- [緩存標簽](#cache-tags)
- [寫入被標記的緩存項](#storing-tagged-cache-items)
- [訪問被標記的緩存項](#accessing-tagged-cache-items)
- [移除被標記的緩存項](#removing-tagged-cache-items)
- [增加自定義的緩存驅動](#adding-custom-cache-drivers)
- [寫驅動](#writing-the-driver)
- [注冊驅動](#registering-the-driver)
- [緩存事件](#events)
<a name="configuration"></a>
## 配置信息
Laravel 給多種緩存系統提供豐富而統一的 API,緩存配置信息位于 `config/cache.php`,在這個文件中你可以為你的應用程序指定默認的緩存驅動,Laravel 支持當前流行的緩存系統,如非常棒的 [Memcached](http://memcached.org) 和 [Redis](http://redis.io) 。
緩存配置信息文件中也包括很多其他選項,你可以在文件中找到這些選項,請確保你看過這些選項說明。Laravel 默認使用將序列化緩存對象保存在文件系統中的 `file` 緩存驅動,對于大型應用程序而言,推薦你使用如 Memcached 或者 Redis 這樣更強大的緩存驅動。你甚至可以為一個驅動配置多個緩存配置信息。
<a name="driver-prerequisites"></a>
### 驅動前提條件
#### 數據庫
當使用 `database` 緩存驅動時,你需要配置一個用來存放緩存項的數據庫表,下面是一個 `Schema` 數據表結構聲明的示例:
Schema::create('cache', function($table) {
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});
> {tip} 你也可以使用 `php artisan cache:table` 這個 Artisan 命令生成一個有合適數據表結構的 migration 。
#### Memcached
使用 Memcached 驅動需要安裝 [Memcached PECL 擴展包](http://pecl.php.net/package/memcached) 。你可以把所有 Memcached 服務器都列在 `config/cache.php` 這個配置信息文件中:
'memcached' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100
],
],
你也可以把 `host` 選項配置到 UNIX 的 socket 路徑中。如果你這樣配置了,`port` 選項應該設置為 `0` :
'memcached' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
#### Redis
在使用 Redis 作為 Laravel 的緩存驅動前,你需要通過 Composer 安裝 `predis/predis` 擴展包 (~1.0) 。
關于配置 Redis 的更多信息,請參考 [Laravel 文檔頁面](/docs/{{version}}/redis#configuration) 。
<a name="cache-usage"></a>
## 緩存的使用
<a name="obtaining-a-cache-instance"></a>
### 獲取一個緩存實例
`Illuminate\Contracts\Cache\Factory` 和 `Illuminate\Contracts\Cache\Repository` [contracts](/docs/{{version}}/contracts) 提供了訪問 Laravel 緩存服務的機制。`Factory` contract 則為你的應用程序定義了訪問所有緩存驅動的機制。`Repository` contract 是典型的用 `cache` 配置信息文件指定你的應用程序默認緩存驅動的實現。
然而,你也可以使用 `Cache` facade,我們將在文檔的后續中介紹。`Cache` facade 提供了方便又簡潔的方法訪問緩存實例:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* Show a list of all users of the application.
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}
#### 訪問多個緩存倉庫
使用`Cache` facade,可通過 `store` 方法來訪問緩存倉庫,傳入 `store` 方法的鍵應該對應一個緩存配置信息文件中的 `stores` 配置信息數組中列出的配置值:
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 10);
<a name="retrieving-items-from-the-cache"></a>
### 從緩存中獲取項目
`Cache` facade 中的 `get` 方法用來從緩存中獲取緩存項,如果緩存中不存在該緩存項,返回 `null` 。你也可以向 `get` 方法傳遞第二個參數,用來指定緩存項不存在時返回的默認值:
$value = Cache::get('key');
$value = Cache::get('key', 'default');
你甚至可以將 `閉包` 作為默認值傳遞。如果指定的緩存項在緩存中不存在,`閉包` 的結果將被返回。傳遞一個閉包允許你延遲從數據庫或外部服務中取出默認值:
$value = Cache::get('key', function() {
return DB::table(...)->get();
});
#### 確認項目是否存在
`has` 方法可以用來檢查一個項目是否存在于緩存中:
if (Cache::has('key')) {
//
}
#### 遞增與遞減值
`遞增` 和 `遞減` 方法可以用來調整緩存中整數項目值。這兩個方法都可以傳入一個可選的第二個參數,用來指示要遞增或遞減多少值:
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
#### 獲取和更新
有時你可能會想從緩存中取出一個項目,但也想在取出的項目不存在時存入一個默認值,例如,你可能會想從緩存中取出所有用戶,或者當用戶不存在時,從數據庫中將這些用戶取出并放入緩存中,你可以使用 Cache::remember 方法實現:
$value = Cache::remember('users', $minutes, function() {
return DB::table('users')->get();
});
如果緩存項在緩存中不存在,則返回給 `remember` 方法的閉包將會被運行,而且閉包的運行結果將會被存放在緩存中。
#### 獲取和刪除
如果你需要從緩存中獲取一個緩存項然后刪除它,你可以使用 `pull` 方法。像 `get` 方法一樣,如果緩存項在緩存中不存在,`null` 將被返回:
$value = Cache::pull('key');
<a name="storing-items-in-the-cache"></a>
### 存儲項目到緩存中
你可以使用 `Cache` facade 的 `put` 方法來存放緩存項到緩存中,當你在緩存中存放緩存項時,你需要使用第三個參數來設定緩存的存放時間:
Cache::put('key', 'value', $minutes);
如果要指定一個緩存項過期的分鐘數,你也可以傳遞一個 `DateTime` 實例來表示該緩存項過期的時間點:
$expiresAt = Carbon::now()->addMinutes(10);
Cache::put('key', 'value', $expiresAt);
#### 寫入目前不存在的項目
`add` 方法只會把暫時不存在于緩存中的緩存項放入緩存,如果存放成功將返回 `true` ,否則返回 `false`:
Cache::add('key', 'value', $minutes);
#### 永久寫入項目
`forever` 方法可以用來將緩存項永久存入緩存中,因為這些緩存項不會過期,所以必須通過 `forget` 方法手動刪除:
Cache::forever('key', 'value');
> {tip} 如果你在使用 Memcached 驅動,那么當緩存達到大小限制時,那些「永久」保存的緩存項可能被移除。
<a name="removing-items-from-the-cache"></a>
### 從緩存中移除項目
你可以使用 `forget` 方法從緩存中移除一個項目:
Cache::forget('key');
也可以使用 `flush` 方法清空所有緩存:
Cache::flush();
> {note} 清空緩存并不會遵從緩存的前綴,并且會將緩存中所有的緩存項刪除。在清除與其它應用程序共享的緩存時應謹慎考慮這一點。
<a name="cache-tags"></a>
## 緩存標簽
> {note} 緩存標簽并不支持使用 `file` 或 `dababase` 的緩存驅動。此外,當在緩存使用多個標簽并「永久」寫入時,類似 `memcached` 的驅動性能會是最佳的,且會自動清除舊的紀錄。
<a name="storing-tagged-cache-items"></a>
### 寫入被標記的緩存項
緩存標簽允許你在緩存中標記關聯的項目,并清空所有已分配指定標簽的緩存值。你可以通過傳入一組標簽名稱的有序數組,以訪問被標記的緩存。舉例來說,讓我們訪問一個被標記的緩存并 `put` 值給它:
Cache::tags(['people', 'artists'])->put('John', $john, $minutes);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);
<a name="accessing-tagged-cache-items"></a>
### 訪問被標記的緩存項
若要獲取一個被標記的緩存項,只要傳遞一樣的有序標簽列表至 `tags` 方法,然后通過你希望獲取的值對應的鍵來調用 `get` 方法:
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
<a name="removing-tagged-cache-items"></a>
### 移除被標記的緩存項
你可以清空已分配的單個標簽或是一組標簽列表中的所有緩存項。例如,下方的語句會把被標記為 `people`、`authors`,或兩者都標記了的緩存都移除。所以,`Anne` 與 `John` 都會被從緩存中移除:
Cache::tags(['people', 'authors'])->flush();
相反的,下方的語句只會刪除被標示為 `authors` 的緩存,所以 `Anne` 會被移除,但 `John` 不會:
Cache::tags('authors')->flush();
<a name="adding-custom-cache-drivers"></a>
## 增加自定義的緩存驅動
<a name="writing-the-driver"></a>
### 寫驅動
為了創建自定義的緩存驅動,首先我們需要部署 `Illuminate\Contracts\Cache\Store` [contract](/docs/{{version}}/contracts) 。所以 MongoDB 緩存實現看起來會像這樣:
<?php
namespace App\Extensions;
use Illuminate\Contracts\Cache\Store;
class MongoStore implements Store
{
public function get($key) {}
public function many(array $keys);
public function put($key, $value, $minutes) {}
public function putMany(array $values, $minutes);
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
public function getPrefix() {}
}
我們只需要通過一個 MongoDB 的連接來實現這些方法。關于如何實現這些方法,可以查看框架源代碼中的 `Illuminate\Cache\MemcachedStore` 。一旦我們的部署完成,我們就可以完成自定義驅動的注冊了。
Cache::extend('mongo', function($app) {
return Cache::repository(new MongoStore);
});
> {tip} 如果你想知道把自定義的緩存驅動代碼放置在哪里,你可以在 `app` 目錄下創建一個 `Extensions` 命名空間。Laravel 沒有硬性規定應用程序的結構,你可以依照你的喜好任意組織你的應用程序。
<a name="registering-the-driver"></a>
### 注冊驅動
通過 Laravel 注冊自定義緩存驅動,我們將用到 `Cache` facade 的 `extend` 方法。`Cache::extend` 的調用會在最新的 Laravel 應用程序默認的 `App\Providers\AppServiceProvider` 的 `boot` 方法中完成。或者你可以創建你自己的服務提供者來放置這些擴展 - 不要忘記在 `config/app.php` 提供者數組中注冊提供者:
<?php
namespace App\Providers;
use App\Extensions\MongoStore;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;
class CacheServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Cache::extend('mongo', function($app) {
return Cache::repository(new MongoStore);
});
}
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
}
傳遞給 `extend` 方法的第一個參數是驅動名稱。這取決于你的 `config/cache.php` 配置信息文件的 `driver` 選項。第二個參數為一個應該返回 `Illuminate\Cache\Repository` 實例的閉包。這個閉包將傳遞一個 [service container](/docs/{{version}}/container) 的 `$app` 實例。
一旦你的擴展被注冊,就可以輕松的更新 `config/cache.php` 配置信息文件的 `driver` 選項為你的擴展名稱。
<a name="events"></a>
## 緩存事件
為了在每一次緩存操作時執行代碼,你可以監聽緩存觸發的事件 [事件](/docs/{{version}}/events) 。一般來說,你必須將這些事件監聽器放置在 `EventServiceProvider` :
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\LogCacheHit',
],
'Illuminate\Cache\Events\CacheMissed' => [
'App\Listeners\LogCacheMissed',
],
'Illuminate\Cache\Events\KeyForgotten' => [
'App\Listeners\LogKeyForgotten',
],
'Illuminate\Cache\Events\KeyWritten' => [
'App\Listeners\LogKeyWritten',
],
];
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@houfei](https://github.com/houfei) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/3472_1452945992.jpeg?imageView2/1/w/100/h/100"> | 翻譯 | 玩咖啡 & 鏟屎奴 & 努力回頭做碼農 [@houfei](https://github.com/houfei) at Github |
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 錯誤與日志
- 開發環境
- HomeStead
- Valet
- 核心概念
- 服務容器
- 服務提供者
- 門面(facades)
- contracts
- HTTP層
- 路由
- 中間件
- CSRF保護
- 控制器
- 請求
- 響應
- Session
- 表單驗證
- 視圖與模板
- 視圖
- Blade模板
- 本地化
- Javascript與CSS
- 入門指南
- laravel-elixir
- 安全
- 用戶認證
- 用戶授權
- 重置密碼
- API授權
- 加密解密
- 哈希
- 綜合話題
- 廣播系統
- 緩存系統
- 事件系統
- 文件存儲
- 郵件發送
- 消息通知
- 隊列
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent集合
- 修改器
- 序列化
- Artisan控制臺
- Artisan 命令行
- 任務調度
- 測試
- 快速入門
- 應用程序測試
- 數據庫測試
- 模擬器
- 官方擴展包
- Cashier交易包
- Envoy 部署工具
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 附錄
- 集合
- 輔助函數
- 擴展包開發
- 交流說明