恥知らずのウェブエンジニア -web engineer, shameless

これは一歩を踏み出すことができない者たちのブログ

PSR-6(Caching Interface)を見ていく

要約ですので、所々省いている箇所あります。

オリジナルはこちら

www.php-fig.org

導入

  • キャッシングはパフォーマンス向上の一般的な手法です。キャッシングライブラリを実装することはフレームワーク、ライブラリの一般機能の1つです
  • これは複数のライブラリがそれぞれ独自のレベルの機能をもったキャッシングライブラリを持つ状態を招きます。これらの差異によって、開発者に必要/不必要に関係なく複数システムを学ばなければいけません
  • 加えて、キャッシングライブラリの開発者は、限られたフレームワークのみサポートするか、多数のアダプタクラスを実装するかの選択に迫られます。

  • キャッシングシステムの共通インターフェースはそれらの問題を解決します。ライブラリ、フレームワーク開発者は、希望する動作のライブラリを利用できます。

  • キャッシングライブラリ開発者は1つのインターフェースを実装するだけでよい。

ゴール

  • このPSRのゴールは、開発者がカスタマイズの必要なく、既存のフレームワーク、システムにキャッシングライブラリを統合できるようにすることです

定義

ライブラリ呼び出し

  • ライブラリ、コードはキャッシュサービスを必要とします。
  • ライブラリはこの標準インターフェースを実装することでキャッシングサービスを利用することができますが、キャッシングサービスの実装知識は必要ありません

ライブラリの実装

  • こにライブラリは、どんなライブラリにもキャッシングサービスを提供するためこの標準を実装する責任がある
  • 実装ライブラリは、Cache\CacheItemPoolInterfaceCache\CacheItemInterfaceを実装するクラスを提供しなければいけない
  • 実装ライブラリは、下記に記載する最小TTLを秒単位でサポートしなければならない

TTL

  • キャッシュアイテムの生存時間(TTL - The Time To Live)はキャッシュされてから失効するまで時間のこと
  • TTLは通常、intの秒数またはDateIntervalで定義する

有効期限

  • キャッシュアイテムが失効する時の時刻
  • これはキャッシュされた時刻にTTLを足すことで計算されるが、明示的にDateTimeオブジェクトで定義してもよい
  • 実装ライブラリは有効期限前にキャッシュを失効してもよい
  • もし有効期限が指定されない場合は、デフォルト値を使っても良い。デフォルト値が設定されていな場合は、無期限にキャッシュしなければならない

キャッシュキー

  • キャッシュされたアイテムを一意に識別する1文字以上の文字列
  • 実装ライブラリは、UTF-8エンコーディングで最大64文字のA-Z, a-z, 0-9, _, .で構成されるキーをサポートしなければならない
  • 実装ライブラリは追加で、その他の文字列/エンコーディング/文字列長をサポートしてもよいが、少なくとも最小限はサポートしなければいけない
  • ライブラリはキーストリングスを適切なエスケープをする責任がありますが、オリジナルの未変更のキーストリングスを返せるなければいけません
  • {}()/\@:これらの文字列は将来の仕様変更に備えて予約されていので、サポートしてはいけない

Hit

  • 呼び出すライブラリからのキーでアイテムをリクエストされ、キーにマッチする値が見つかり、有効期限ではなく、なんらかの理由で失効になっていない時にキャッシュヒットが起こります。
  • 呼び出すライブラリは、すべてのget()コールで、isHit()を使って確認すべきです

Miss

  • キャッシュミスはキャッシュヒットの逆
  • リクエストされたキーにマッチするものがない、有効期限が切れている、なんらかの理由で無効になっている時はキャッシュミス
  • 有効期限切れの値はキャッシュミスにならなければいけない

Deferred

  • 遅延キャッシュは、アイテムがプールによってすぐに永続化されないことを意味します
  • プールオブジェクトはいくつかのストレージエンジンでサポートされているバルクセットを利用するためキャッシュを遅延してもよい
  • プールは遅延されたアイテムを最終的に永続化し、ロストさせてはいけない。そして呼び出すライブラリが永続化リクエスト前に保持してもよい
  • 呼び出すライブラリがcommit()を読んだ時はすべての遅延キャッシュを永続化させなければいけない
  • 実装ライブラリは、save()タイムアウト、max-itemsチェックやその他適切なロジックで遅延アイテムを永続化してよい
  • 遅延キャッシュされたアイテムがリクエストされた時は、永続化されていなくとも遅延されたアイテムを返却しないといけない

Data

  • 実装ライブラリはシリアライズできるPHPデータすべてをサポートしないといけない

    • Strings
    • Integers
    • Floats
    • Boolean
    • Null
    • Arrays
    • Object
  • 全てのデータは実装ライブラリに渡された形のまま、型も含め返却されなければいけない

  • 実装ライブラリは、内部的にPHPserialize()/unserialize()を使って良い、これは必須ではない
  • なんらかの理由で正確な値が返却できない場合、実装ライブラリは破損したデータを返すより、キャッシュミスを返さなければいけない

Key Concepts

Pool

  • プールはキャッシュシステム内のアイテムの集合を表す。プールはすべてのアイテムが含まれる論理的なリポジトリ
  • すべてのキャッシュ可能なアイテムはプールからアイテムオブジェクトとして検索され、すべてのキャッシュオブジェクトはプールを介して対話する

Items

  • アイテムはプール内の単一のkey/valueのペアを表す。keyはアイテムのユニークな識別子で、不変でなければいけない。値はいつでも変更あってもよい

Error handling

  • キャッシングはパフォーマンスにとって重要ですが、アプリケーション機能の重要な部分ではありません。なので、キャッシュシステムのエラーはアプリケーションのエラーになるべきではありません
  • 実装ライブラリは、インターフェースで定義された以上のexceptionをthrowしてはいけません。そしてキャッシュシステムでのエラーをトラップして上げるべきではありません

  • 実装ライブラリはそのようなログはエラーをログに残すか管理者に報告すべきです

  • もし呼び出しライブラリが1つかそれ以上の削除済みか、プールがクリアさてれいるアイテムをリクエストされ、キーが存在しない場合でもエラーとしてはいけません

Interfaces

CacheItemInterface

  • CacheItemInterfaceはキャッシュシステム内のアイテムを定義
  • 各アイテムオブジェクトは特定のキーに関連付けられていなければなりません。通常はCache\CacheItemPoolInterfaceオブジェクトによって渡されます。
  • Cache\CacheItemPoolInterfaceはキャッシュアイテムの格納、検索をカプセル化します
  • どのCache\CacheItemInterfaceCache\CacheItemPoolInterfaceから生成され、必要なセットアップとユニークキーとオブジェクトを関連付けます
  • Cache\CacheItemInterfaceはどのデータ型でも格納、検索できなければいけません

  • 呼び出しライブラリは自身で、アイテムオブジェクトを生成してはいけません

  • プールオブジェクトのgetItem()メソッドからリクエストされるべきです
  • 呼び出しライブラリはあるライブラリから生成されたアイテムオブジェクトが他のライブラリと互換性があると想定すべきではありません

CacheItemPoolInterface

  • Cache\CacheItemPoolInterfaceの優先目的は呼び出しライブラリからキーを受け付け、Cache\CacheItemInterfaceオブジェクトを返却することです
  • キャッシュコレクションと対話することも重要ポイント
  • プールの設定、初期化は実装ライブラリに任されます

CacheItemInterface

<?php

namespace Psr\Cache;

/**
 * CacheItemInterface defines an interface for interacting with objects inside a cache.
 */
interface CacheItemInterface
{
    /**
     * Returns the key for the current cache item.
     */
    public function getKey();

    /**
     * Retrieves the value of the item from the cache associated with this object's key.
     */
    public function get();

    /**
     * Confirms if the cache item lookup resulted in a cache hit.
     */
    public function isHit();

    /**
     * Sets the value represented by this cache item.
     */
    public function set($value);

    /**
     * Sets the expiration time for this cache item.
     */
    public function expiresAt($expiration);

    /**
     * Sets the expiration time for this cache item.
     */
    public function expiresAfter($time);
}

CacheItemPoolInterface

<?php

namespace Psr\Cache;

/**
 * CacheItemPoolInterface generates CacheItemInterface objects.
 */
interface CacheItemPoolInterface
{
    /**
     * Returns a Cache Item representing the specified key.
     */
    public function getItem($key);

    /**
     * Returns a traversable set of cache items.
     */
    public function getItems(array $keys = array());

    /**
     * Confirms if the cache contains specified cache item.
     */
    public function hasItem($key);

    /**
     * Deletes all items in the pool.
     */
    public function clear();

    /**
     * Removes the item from the pool.
     */
    public function deleteItem($key);

    /**
     * Removes multiple items from the pool.
     */
    public function deleteItems(array $keys);

    /**
     * Persists a cache item immediately.
     */
    public function save(CacheItemInterface $item);

    /**
     * Sets a cache item to be persisted later.
     */
    public function saveDeferred(CacheItemInterface $item);

    /**
     * Persists any deferred cache items.
     */
    public function commit();
}

パフォーマンスアップには、各種キャッシュが欠かせません。

しかし、そのキャッシュの処理がライブラリごとにバラバラだと何かと面倒なことが起こります。
また共通化がされていないと、キャッシュに使うサービスもmemcached,redis,fileなどなど切り替えたりするのも面倒です。

そこでインターフェースを合わせましょうっていう流れかと。
目標的にはPSR-3(Logger Interface)と同じような感じですね!

しかしざっと主要なフレームワークを見ると現状は必ずしも実装されているわけではない模様・・・

ぱっと見symfonyぐらいでしょうか。。。

GitHub - symfony/cache: [READ-ONLY] Subtree split of the Symfony Cache Component

単にkey/valで欲しいだけなので、pool -> item obj -> valはちょっと遠回りな印象
これの簡略版がPSR-16(Simple Cache)として提案されています

PSR-16: Common Interface for Caching Libraries - PHP-FIG


次はPSR-7(HTTP Message Interface)へ・・・

PSR-7: HTTP message interfaces - PHP-FIG