Symfony Component Advent Calendar 2022の16日目の記事です。
最初に
SymfonyはPHPのフレームワークのひとつです。しかし、公式サイトの説明文には
Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
(SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。)
と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。
今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。
※記事内ではautoloadのインポートは省略します。
結果を一定期間保持する、"Cache"
Cacheは、処理結果を一定期間保持し、その値を返すことでパフォーマンス向上を行うコンポーネントです。
実はちゃんと使ったことがないコンポーネントです。が、ざっとドキュメントを読んでみると非常に魅力的なコンポーネントでした。
インストール
composer require symfony/cache
キャッシュの作成・利用
値をキャッシュするにはCache
オブジェクトを使います。get()
メソッドで、取得するためのキーと取得できなかった場合の処理(= キャッシュする値)を記述します。
use Symfony\Contracts\Cache\ItemInterface;
class SompleCommand extends Command
{
public function __construct(private readonly CacheInterface $cache)
{
parent::__construct();
}
public function execute(InputInterface $input, OutputInterface $output): int
{
// キャッシュの作成・利用
$value = $this->cache->get('my_value', function (ItemInterface $item) {
$randomValue = rand(0, 100); // ランダムな値
$item->expiresAfter(30); // 30秒間キャッシュ
return $randomValue;
});
// 最初のランダムな値が28だった場合、30秒間はコマンドを何度実行しても28が出力される。
$io->success($value);
}
}
ItemInterface
はキャッシュの設定が行えるアイテムクラスです。各キーごとにオブジェクトが生成されます。
キャッシュの設定
通常、キャッシュはvar/cache
にファイルとして保存されますが、他にもいくつかの保存先が利用でき、設定ファイルでアダプター(&プロバイダー)を設定することで切り替えができます。
framework:
cache:
app: cache.adapter.filesystem
system: cache.adapter.system
framework.cache.app
はアプリケーション側(= 自分達が作るコード側)のプール設定、framework.cache.system
はSymfony側のプール設定になります。基本はapp
側のみさわることになると思います。用意されているアダプターは以下の通りです。
設定名 | 保存先 |
---|---|
cache.adapter.apcu | APC User Cache |
cache.adapter.array | メモリー内(1プロセス内のみ生きることができる) |
cache.adapter.filesystem | ファイル(var/cache) |
cache.adapter.memcached | Memcached |
cache.adapter.pdo | DB |
cache.adapter.psr6 | PSR6準拠 |
cache.adapter.redis | Redis |
cache.adapter.redis_tag_aware | Redis(タグベース) |
cache.adapter.system | Symfony用、appでは使わない |
プロバイダーの設定が必要な場合は、別途設定を追記します。
framework:
cache:
app: cache.adapter.filesystem
system: cache.adapter.system
default_redis_provider: 'redis://localhost'
また、app
, system
以外のプールも用意することができ、プール名のキャメルケースにした引数をコンストラクタに持つことでオートワイヤリングできます。
framework:
cache:
pools:
my_great.cache:
adapter: cache.adapter.redis
class SomeService
{
public function __construct(CacheInterface $myGreatCache)
{
}
}
HTTPレスポンスのキャッシュ
HTTPレスポンスのキャッシュはまた別の設定・記述が必要です。まず、framework.yaml
でキャッシュを有効化します。
framework:
http_cache: true
そして、出力するレスポンスオブジェクトでsetPublic()
, setMaxAge()
メソッドを呼び出します。
class ItemController extends AbstractController
{
public function index(ItemRepository $itemRepository): Response
{
$items = $itemRepository->findBy(['isPublished' => true]);
$response = $this->render('item/index.html.twig', [
'items' => $items,
]);
$response
->setPublic() // "Cache-Control"に"public"追加
->setMaxAge(60) // "Cache-Control"に"maxage=60"追加
return $response;
}
}
これにより、レスポンスヘッダにCache-Controle: public, maxage=60
が追加され、60秒間はコンテンツがキャッシュされます。
Symfony6.2から! アトリビュート設定
Symfony6.2ではアトリビュートで指定できるようになり、さらに設定がしやすくなります。
+ use Symfony\Component\HttpKernel\Attribute\Cache;
class ItemController extends AbstractController
{
+ #[Cache(public: true, maxage: 60)]
public function index(ItemRepository $itemRepository): Response
{
$items = $itemRepository->findBy(['isPublished' => true]);
+ return $this->render('item/index.html.twig', [
- $response = $this->render('item/index.html.twig', [
'items' => $items,
]);
-
- $response
- ->setPublic() // "Cache-Control"に"public"追加
- ->setMaxAge(60) // "Cache-Control"に"maxage=60"追加
-
- return $response;
}
}
まとめ
今回はCache
を紹介しました。キャッシュは扱いがとても難しいですが、ちゃんと使っていくとパフォーマンスが飛躍的に向上します。
特にSymfony6.2からはアトリビュートでの指定ができるので、トライ&エラーが非常にやりやすくなるので、試してみる価値大かなと思います。