Laravel 10.x キャッシュ

イントロダクション

アプリケーションによって実行されるデータ取得または処理タスクの一部は、CPUに負荷がかかるか、完了するまでに数秒かかる場合があります。この場合、取得したデータを一時的にキャッシュして、同じデータに対する後続のリクエストですばやく取得できるようにするのが一般的です。キャッシュするデータは通常、MemcachedRedisなどの非常に高速なデータストアに保存します。

幸いLaravelはさまざまなキャッシュバックエンドに表現力豊かで統一されたAPIを提供し、その超高速データ取得を利用してWebアプリケーションを高速化できるようにします。

設定

アプリケーションのキャッシュ設定ファイルはconfig/cache.phpにあります。このファイルでは、アプリケーション全体でデフォルトで使用するキャッシュドライバを指定します。Laravelは、MemcachedRedisDynamoDBなどの一般的なキャッシュバックエンドとリレーショナルデータベースをはじめからサポートしています。さらに、ファイルベースのキャッシュドライバも利用可能で、arrayおよび「null」キャッシュドライバは、自動テストに便利なキャッシュバックエンドを提供します。

キャッシュ設定ファイルには、ファイル内のコメントで説明しているさまざまな他のオプションも存在しているため、これらのオプションを必ずお読みください。デフォルトでLaravelは、シリアルライズ後にオブジェクトをサーバのファイルシステムにキャッシュするfileキャッシュドライバを使用するように設定しています。大規模なアプリケーションの場合は、MemcachedやRedisなどのより堅牢なドライバを使用することをおすすめします。同じドライバに対して複数のキャッシュ設定を構築することもできます。

ドライバ要件

データベース

databaseキャッシュドライバを使用する場合は、キャッシュアイテムを格納するためのテーブルを用意する必要があります。以下は、そのテーブルのためのSchema定義の例です。

Schema::create('cache', function (Blueprint $table) {
    $table->string('key')->unique();
    $table->text('value');
    $table->integer('expiration');
});

Note: php artisan cache:table Artisanコマンドを使用して、適切なスキーマのマイグレーションを生成することもできます。

Memcached

Memcachedドライバを使用するには、Memcached PECLパッケージがインストールされている必要があります。すべてのMemcachedサーバをconfig/cache.php設定ファイルにリストしてください。このファイルには、設定しやすいようにmemcached.serversエントリがはじめから用意しています。

'memcached' => [
    'servers' => [
        [
            'host' => env('MEMCACHED_HOST', '127.0.0.1'),
            'port' => env('MEMCACHED_PORT', 11211),
            'weight' => 100,
        ],
    ],
],

必要に応じて、hostオプションをUNIXソケットパスに設定できます。これを行う場合は、portオプションを0に設定する必要があります。

'memcached' => [
    [
        'host' => '/var/run/memcached/memcached.sock',
        'port' => 0,
        'weight' => 100
    ],
],

Redis

LaravelでRedisキャッシュを使用する前に、PECLを介してPhpRedis PHP拡張機能をインストールするか、Composerを介してpredis/predisパッケージ(〜1.0)をインストールする必要があります。Laravel Sailにはすでにこの拡張機能が含まれています。さらに、Laravel ForgeLaravel Vaporなどの公式のLaravel開発プラットフォームには、デフォルトでPhpRedis拡張機能がインストールされています。

Redisの設定の詳細については、Laravelドキュメントページを参照してください。

DynamoDB

DynamoDBキャッシュドライバを使用する前に、すべてのキャッシュデータを格納するためのDynamoDBテーブルを作成する必要があります。通常、このテーブルはcacheという名前です。ただし、アプリケーションのcache設定ファイル内のstores.dynamodb.table設定値の値に基づいてテーブルに名前を付ける必要があります。

このテーブルには、アプリケーションのcache設定ファイル内のstores.dynamodb.attributes.key設定項目の値に対応する名前の、文字列パーティションキーもあります。デフォルトでは、パーティションキーはkeyという名前にする必要があります。

キャッシュ使用法

キャッシュインスタンスの取得

キャッシュ保存域インスタンスを取得するには、Cacheファサードを使用できます。これは、このドキュメント全体で使用します。Cacheファサードは、Laravelキャッシュ契約の基盤となる実装への便利で簡潔なアクセスを提供します。

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    /**
     * アプリケーションのすべてのユーザーのリストを表示
     */
    public function index(): array
    {
        $value = Cache::get('key');

        return [
            // ...
        ];
    }
}

複数のキャッシュ保存域へのアクセス

Cacheファサードを使用すると、storeメソッドを介してさまざまなキャッシュ保存域にアクセスできます。storeメソッドに渡されるキーは、cache設定ファイルのstores設定配列にリストされている保存域の1つに対応している必要があります。

$value = Cache::store('file')->get('foo');

Cache::store('redis')->put('bar', 'baz', 600); // 10分

キャッシュからのアイテム取得

Cacheファサードのgetメソッドは、キャッシュからアイテムを取得するために使用します。アイテムがキャッシュに存在しない場合、nullを返します。必要に応じて、アイテムが存在しない場合に返されるデフォルト値を指定する2番目の引数をgetメソッドに渡すことができます。

$value = Cache::get('key');

$value = Cache::get('key', 'default');

デフォルト値としてクロージャを渡すこともできます。指定されたアイテムがキャッシュに存在しない場合、クロージャの結果が返されます。クロージャを渡すことで、データベースまたは他の外部サービスからのデフォルト値の取得を延期できるようになります。

$value = Cache::get('key', function () {
    return DB::table(/* ... */)->get();
});

アイテムの存在を判定

hasメソッドを使用して、アイテムがキャッシュに存在するかを判定できます。このメソッドは、アイテムが存在するがその値がnullの場合にも、falseを返します。

if (Cache::has('key')) {
    // ...
}

値の増減

incrementメソッドとdecrementメソッドを使用して、キャッシュ内の整数項目の値を増減できます。これらのメソッドは両方とも、アイテムの値をインクリメントまたはデクリメントする数を示すオプションの2番目の引数を取ります。

// 存在しない場合、値を初期設定
Cache::add('key', 0, now()->addHours(4));

// 値の増分と減分
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);

取得か保存

時に、キャッシュからアイテムを取得したいが、リクエストされたアイテムが存在しない場合はデフォルト値を保存したい場合があります。たとえば、すべてのユーザーをキャッシュから取得するか、存在しない場合はデータベースから取得してキャッシュに追加できます。これは、Cache::rememberメソッドを使用して行えます。

$value = Cache::remember('users', $seconds, function () {
    return DB::table('users')->get();
});

アイテムがキャッシュに存在しない場合、rememberメソッドに渡されたクロージャが実行され、その結果がキャッシュに配置されます。

rememberForeverメソッドを使用して、キャッシュからアイテムを取得するか、アイテムが存在しない場合は永久に保存できます。

$value = Cache::rememberForever('users', function () {
    return DB::table('users')->get();
});

取得後に削除

キャッシュからアイテムを取得してからアイテムを削除する必要がある場合は、pullメソッドを使用できます。getメソッドと同様に、アイテムがキャッシュに存在しない場合はnullが返されます。

$value = Cache::pull('key');

キャッシュへのアイテム保存

Cacheファサードでputメソッドを使用して、アイテムをキャッシュに保存できます。

Cache::put('key', 'value', $seconds = 10);

保存時間がputメソッドに渡されない場合、アイテムは無期限に保存されます。

Cache::put('key', 'value');

秒数を整数として渡す代わりに、キャッシュするアイテムの有効期限を表すDateTimeインスタンスを渡すこともできます。

Cache::put('key', 'value', now()->addMinutes(10));

存在しない場合は保存

addメソッドは、アイテムがキャッシュストアにまだ存在しない場合にのみ、アイテムをキャッシュに追加します。アイテムが実際にキャッシュに追加された場合、メソッドはtrueを返します。それ以外の場合にメソッドはfalseを返します。addメソッドはアトミック操作です。

Cache::add('key', 'value', $seconds);

アイテムを永久に保存

foreverメソッドを使用して、アイテムをキャッシュに永続的に保存できます。保存アイテムは期限切れにならないため、forgetメソッドを使用して手作業でキャッシュから削除する必要があります。

Cache::forever('key', 'value');

Note: Memcachedドライバを使用している場合、「永久に」保存されているアイテムは、キャッシュがサイズ制限に達すると削除される可能性があります。

キャッシュからのアイテム削除

forgetメソッドを使用してキャッシュからアイテムを削除できます。

Cache::forget('key');

有効期限の秒数をゼロまたは負にすることで、アイテムを削除することもできます。

Cache::put('key', 'value', 0);

Cache::put('key', 'value', -5);

flushメソッドを使用してキャッシュ全体をクリアできます。

Cache::flush();

Warning!! キャッシュのフラッシュは、設定したキャッシュの「プレフィックス」を尊重せず、キャッシュからすべてのエントリを削除します。他のアプリケーションと共有するキャッシュをクリアするときは、これを慎重に検討してください。

キャッシュヘルパ

Cacheファサードの使用に加え、グローバルなcache関数を使用して、キャッシュによるデータの取得および保存もできます。cache関数が単一の文字列引数で呼び出されると、指定されたキーの値を返します。

$value = cache('key');

キーと値のペアの配列と有効期限を関数に指定すると、指定された期間、値がキャッシュに保存されます。

cache(['key' => 'value'], $seconds);

cache(['key' => 'value'], now()->addMinutes(10));

cache関数を引数なしで呼び出すと、Illuminate\Contracts\Cache\Factory実装のインスタンスが返され、他のキャッシュメソッドを呼び出せます。

cache()->remember('users', $seconds, function () {
    return DB::table('users')->get();
});

Note: グローバルなcache関数の呼び出しをテストするときは、ファサードをテストするのようにCache::shouldReceiveメソッドを使用できます。

アトミックロック

Warning!! この機能を利用するには、アプリケーションのデフォルトのキャッシュドライバとして、memcachedredisdynamodbdatabasefilearrayキャッシュドライバを使用する必要があります。さらに、すべてのサーバが同じ中央キャッシュサーバと通信している必要があります。

ドライバ要件

データベース

databaseキャッシュドライバを使用する場合は、アプリケーションのキャッシュロックを含むテーブルを設定する必要があります。以下にテーブルのSchema宣言の例を示します。

Schema::create('cache_locks', function (Blueprint $table) {
    $table->string('key')->primary();
    $table->string('owner');
    $table->integer('expiration');
});

Note: cache:table Artisanコマンドを使用し、データベースドライバのキャッシュテーブルを作成した場合、作成したマイグレーションには、あらかじめcache_locksテーブルの定義が含まれています。

ロック管理

アトミックロックを使用すると、競合状態を気にすることなく分散ロックを操作できます。たとえば、Laravel Forgeは、アトミックロックを使用して、サーバ上で一度に1つのリモートタスクのみが実行されるようにしています。Cache::lockメソッドを使用してロックを作成および管理できます。

use Illuminate\Support\Facades\Cache;

$lock = Cache::lock('foo', 10);

if ($lock->get()) {
    // ロックを10秒間取得

    $lock->release();
}

getメソッドもクロージャを受け入れます。クロージャが実行された後、Laravelは自動的にロックを解除します。

Cache::lock('foo', 10)->get(function () {
    // ロックを10秒間取得し、自動的に開放
});

リクエストした時点でロックが利用できない場合に、指定された秒数待つようにLaravelへ指示できます。指定された制限時間内にロックを取得できない場合、Illuminate\Contracts\Cache\LockTimeoutExceptionを投げます。

use Illuminate\Contracts\Cache\LockTimeoutException;

$lock = Cache::lock('foo', 10);

try {
    $lock->block(5);

    // ロック取得を最大5秒待つ
} catch (LockTimeoutException $e) {
    // ロック取得失敗
} finally {
    $lock?->release();
}

上記の例は、クロージャをblockメソッドに渡すことで簡略化できます。クロージャがこのメソッドに渡されると、Laravelは指定された秒数の間ロックを取得しようとし、クロージャが実行されると自動的にロックを解放します。

Cache::lock('foo', 10)->block(5, function () {
    // ロック取得を最大5秒待つ
});

プロセス間でのロック管理

あるプロセスでロックを取得し、別のプロセスでそれを解放したい場合があります。たとえば、Webリクエスト中にロックを取得し、そのリクエストによってトリガーされたキュー投入済みジョブの終了時にロックを解放したい場合があるでしょう。このシナリオでは、ロックのスコープ付き「所​​有者トークン」をキュー投入済みジョブに渡し、ジョブが渡されたトークンを使用してロックを再インスタンス化できるようにする必要があります。

以下の例では、ロックが正常に取得された場合に、キュー投入済みジョブをディスパッチします。さらに、ロックのownerメソッドを介して、ロックの所有者トークンをキュー投入済みジョブに渡します。

$podcast = Podcast::find($id);

$lock = Cache::lock('processing', 120);

if ($lock->get()) {
    ProcessPodcast::dispatch($podcast, $lock->owner());
}

アプリケーションのProcessPodcastジョブ内で、所有者トークンを使用してロックを復元し、解放できます。

Cache::restoreLock('processing', $this->owner)->release();

現在の所有者を尊重せずにロックを解放したい場合は、forceReleaseメソッドを使用できます。

Cache::lock('processing')->forceRelease();

カスタムキャッシュドライバの追加

ドライバの作成

カスタムキャッシュドライバを作成するには、最初にIlluminate\Contracts\Cache\Store契約を実装する必要があります。したがって、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, $seconds) {}
    public function putMany(array $values, $seconds) {}
    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接続を使用してこれらの各メソッドを実装する必要があります。これらの各メソッドを実装する方法の例については、LaravelフレームワークのソースコードIlluminate\Cache\MemcachedStoreをご覧ください。実装が完了したら、Cacheファサードのextendメソッドを呼び出してカスタムドライバの登録を完了してください。

Cache::extend('mongo', function (Application $app) {
    return Cache::repository(new MongoStore);
});

Note: カスタムキャッシュドライバコードをどこに置くか迷っている場合は、appディレクトリ内にExtensions名前空間を作成できます。ただし、Laravelには厳密なアプリケーション構造がなく、好みに応じてアプリケーションを自由にオーガナイズできることに注意してください。

ドライバの登録

カスタムキャッシュドライバをLaravelに登録するには、Cacheファサードでextendメソッドを使用します。他のサービスプロバイダはbootメソッド内でキャッシュされた値を読み取ろうとする可能性があるため、bootingコールバック内にカスタムドライバを登録します。bootingコールバックを使用することで、アプリケーションのサービスプロバイダでbootメソッドが呼び出される直前で、すべてのサービスプロバイダでregisterメソッドが呼び出された後にカスタムドライバが登録されるようにすることができます。アプリケーションのApp\Providers\AppServiceProviderクラスのregisterメソッド内にbootingコールバックを登録します。

<?php

namespace App\Providers;

use App\Extensions\MongoStore;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * アプリケーションの全サービスの登録
     */
    public function register(): void
    {
        $this->app->booting(function () {
             Cache::extend('mongo', function (Application $app) {
                 return Cache::repository(new MongoStore);
             });
         });
    }

    /**
     * 全アプリケーションサービスの初期起動処理
     */
    public function boot(): void
    {
        // ...
    }
}

extendメソッドに渡す最初の引数はドライバの名前です。これは、config/cache.php設定ファイルのdriverオプションに対応させます。2番目の引数は、Illuminate\Cache\Repositoryインスタンスを返す必要があるクロージャです。クロージャには、サービスコンテナのインスタンスである$appインスタンスが渡されます。

拡張機能を登録したら、config/cache.php設定ファイルのdriverオプションを拡張機能の名前に更新します。

イベント

キャッシュ操作のどこででもコードを実行するには、キャッシュが発生させるイベントをリッスンしてください。通常、これらのイベントリスナはアプリケーションのApp\Providers\EventServiceProviderクラス内に配置する必要があります。

use App\Listeners\LogCacheHit;
use App\Listeners\LogCacheMissed;
use App\Listeners\LogKeyForgotten;
use App\Listeners\LogKeyWritten;
use Illuminate\Cache\Events\CacheHit;
use Illuminate\Cache\Events\CacheMissed;
use Illuminate\Cache\Events\KeyForgotten;
use Illuminate\Cache\Events\KeyWritten;

/**
 * アプリケーションのイベントリスナマップ
 *
 * @var array
 */
protected $listen = [
    CacheHit::class => [
        LogCacheHit::class,
    ],

    CacheMissed::class => [
        LogCacheMissed::class,
    ],

    KeyForgotten::class => [
        LogKeyForgotten::class,
    ],

    KeyWritten::class => [
        LogKeyWritten::class,
    ],
];

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる