#介绍

设置缓存是每个项目提升标签的常用手段,缓存库是很多框架一个最通用的功能。本篇针对以下情况,各框架都推出多种多样功能的缓存库。这些差别使得开发人员不得不学习多种系统,而有些可能是他们不需要的功能。此外,缓存库的开发人员同样面临着一个选择,是指支持一个有限数量的几个框架还是创建一堆庞大的适配器类。

一个通用的缓存系统接口会解决这些问题。库和框架的开发人员能够知道缓存系统会按照他所预期的方式工作,缓存系统的开发人员只需要实现单一的接口,而不用去开发各种各样的适配器。

文档中关键词 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” 的含义参见 RFC 2119

#目标

本PSR的目标是能够让开发人员能够创建一个能够整合到现有框架和系统而不需要自定义开发的面向缓存的库。

#详细描述

  • Calling Library - 库或者代码需要实际的缓存服务。这个库会利用缓存服务来实现标准里的接口,但是它是不清楚缓存服务的实现的。
  • Implementing Library - 这个库负责实现本标准,以便给任何Calling Library提供缓存服务。Implementing Library提供的类MUST实现Cache\CacheItemPoolInterfaceCache\CacheItemInterface接口。Implementing LibrariesMUST支持TTL,如下面所述要以整秒为最小粒度。
  • TTL - 生存时间 (TTL) 是指一个值从开始被存储到被废弃的时间。TTL一般使用一个表示时间秒数的整数或者一个dateintegerval来表示。
  • Expiration - 但是一个值被设置成废弃时的实际时间。一般通过该值被存储是的时间 + TTL来计算,也被明确的使用DateTime对象指定。

一个 300 秒TTL的值于1:30:00存储,到期时间为1:35:00。

Implementing LibrariesMAY废弃一个值即便它现在还没到期,但是一旦到期MUST把值设置成为到期状态。如果调用库区保存一个值但是没有指定具体的到期时间,或者到期时间或TTL传入的是null,Implementing LibraryMAY使用一个配置好的默认持续时长。如果没有默认的持续时长,Implementing Library MUST解释为要永远存储该值。或者在依赖底层实现的基础上尽可能长。

  • Key - 为至少一个字符并且不重复的字符串。Implementing libraries MUST支持的key的组成:A-Z, a-z, 0-9, “_”, 和 “.”。可以为UTF-8编码的任意顺序组合,最大长度为64个字符。Implementing libraries MAY支持其他字符和编码或者更长的长度,但是必须先支持支持之前提到的最低标准。库负责对key进行转义以更加合适的方式存储,但是MUST能够返回最原始的没有修改过的key。下面的字符预留,以备后续的扩展,MUST NOTImplementing Libraries支持:{}()/\@:
  • Hit - 缓存的命中发生在当调用库时通过key去匹配到对应的值,并且那个值不能是过期或者是由于其他原因无效的。调用库SHOULD确保在所有的get()被调用时都做一次isHit()验证。
  • Miss - 缓存明命反之是缓存错失。缓存错失放生在当调用库时未能通过key匹配到对应的值,或者那个值是过去或者因其他原因无效的。一个过去的值MUST一直认为是你一个缓存错失。
  • Deferred - 一个延时的缓存保存是指一个缓存的值不可以被池立即持久化。一个(Pool)MAY延时持久化一个延时缓存值以便可以利用一些存储引擎支持大批量设置的操作的优势。一个池MUST确保所有的延时缓存最终会被持久化不会丢失,并且MAY持久化好这些值在下次库的Calling Library请求来之前。当Calling Library执行commit()方法所有没有处理的延时的值MUST被持久化。一个Implementing Library MAY 使用任何逻辑以确定何时持久化延时的缓存,比如销毁器去调用save()去持久化,一个定时器或者最大值监测或者其他何时的逻辑。一个延时缓存的请求MUST返回“延时”而不是“未持久化”。

#数据

Implementing Library MUST 支持所有PHP可序列化数据,包括:

  • Strings - 用任何PHP兼容的编码方式编码的,任意长度字符串。
  • Integers - PHP支持的任意长度整数,最大有符号64-bit。
  • Floats - 所有有符号float值.
  • Boolean - True 和 False.
  • Null - null.
  • Arrays - 索引数组,关联数组和有任意维度的多维数组。
  • Object - 任何对象支持无损序列化和反序列化,例如 $o == unserialize(serialize($o))。对象MAY借助PHPSerializable接口、__sleep()__wakeup()方法,或者类似的合适的语法功能。

所有传入Implementing Library 的数据 MUST 被返回的切实和传入的一致。它包含了多种类型。如果存储的是(int) 5,返回的是(string) 5,这样是错误的。Implementing Libraries MAY 在内部使用PHP的serialize()/unserialize()方法,但是不必须这样做。兼容这些是为了使对象有更好的可访问性。

如果由于某种原因,不能返回一个和存储是完全一样的数据,Implementing Library MUST响应一个miss而不是损坏的数据。

#键 概念

##池

池表示缓存系统中多个缓存值的集合。池是一个包含多个缓存值的逻辑存储空间。所有可缓存的值只都可以从池中取出,对所有缓存对象的影响都是通过池发生的。

##值

一个缓存值表示一个池中的键值对。键是一个不重复的独立表示,是不可改变的。值MAY可以在任意时候改变。

#错误处理

因为缓存常常是一个程序的非常重要的组成部分,它应该绝不是一个应用程序的关键部分。因此,一个缓存系统中的错误SHOULD NOT导致应用程序错误。出于这个原因Implementing Libraries MUST NOT抛出异常除非接口中有定义,SHOULD捕获底层数据抛出的任何错误和异常不让他们向上冒泡。

Implementing Library SHOULD记录这些错误或者在合适的情况报告给管理员。

如果Calling Library请求一个或多个被删除的值,或者池是空的。MUST NOT认为是一个错误的情况。

#接口

##CacheItemInterface

CacheItemInterface defines an item inside a cache system. Each Item object MUST be associated with a specific key, which can be set according to the implementing system and is typically passed by the Cache\CacheItemPoolInterface object.

The Cache\CacheItemInterface object encapsulates the storage and retrieval of cache items. Each Cache\CacheItemInterface is generated by a Cache\CacheItemPoolInterface object, which is responsible for any required setup as well as associating the object with a unique Key. Cache\CacheItemInterface objects MUST be able to store and retrieve any type of PHP value defined in the Data section of this document.

Calling Libraries MUST NOT instantiate Item objects themselves. They may only be requested from a Pool object via the getItem() method. Calling Libraries SHOULD NOT assume that an Item created by one Implementing Library is compatible with a Pool from another Implementing Library.

namespace Psr\Cache;

/**
 * CacheItemInterface defines an interface for interacting with objects inside a cache.
 */
interface CacheItemInterface
{
    /**
     * Returns the key for the current cache item.
     *
     * The key is loaded by the Implementing Library, but should be available to
     * the higher level callers when needed.
     *
     * @return string
     *   The key string for this cache item.
     */
    public function getKey();

    /**
     * Retrieves the value of the item from the cache associated with this object's key.
     *
     * The value returned must be identical to the value originally stored by set().
     *
     * If isHit() returns false, this method MUST return null. Note that null
     * is a legitimate cached value, so the isHit() method SHOULD be used to
     * differentiate between "null value was found" and "no value was found."
     *
     * @return mixed
     *   The value corresponding to this cache item's key, or null if not found.
     */
    public function get();

    /**
     * Confirms if the cache item lookup resulted in a cache hit.
     *
     * Note: This method MUST NOT have a race condition between calling isHit()
     * and calling get().
     *
     * @return bool
     *   True if the request resulted in a cache hit. False otherwise.
     */
    public function isHit();

    /**
     * Sets the value represented by this cache item.
     *
     * The $value argument may be any item that can be serialized by PHP,
     * although the method of serialization is left up to the Implementing
     * Library.
     *
     * @param mixed $value
     *   The serializable value to be stored.
     *
     * @return static
     *   The invoked object.
     */
    public function set($value);

    /**
     * Sets the expiration time for this cache item.
     *
     * @param \DateTimeInterface $expiration
     *   The point in time after which the item MUST be considered expired.
     *   If null is passed explicitly, a default value MAY be used. If none is set,
     *   the value should be stored permanently or for as long as the
     *   implementation allows.
     *
     * @return static
     *   The called object.
     */
    public function expiresAt($expiration);

    /**
     * Sets the expiration time for this cache item.
     *
     * @param int|\DateInterval $time
     *   The period of time from the present after which the item MUST be considered
     *   expired. An integer parameter is understood to be the time in seconds until
     *   expiration. If null is passed explicitly, a default value MAY be used.
     *   If none is set, the value should be stored permanently or for as long as the
     *   implementation allows.
     *
     * @return static
     *   The called object.
     */
    public function expiresAfter($time);

}

##CacheItemPoolInterface

The primary purpose of Cache\CacheItemPoolInterface is to accept a key from the Calling Library and return the associated Cache\CacheItemInterface object. It is also the primary point of interaction with the entire cache collection. All configuration and initialization of the Pool is left up to an Implementing Library.

namespace Psr\Cache;

/**
 * CacheItemPoolInterface generates CacheItemInterface objects.
 */
interface CacheItemPoolInterface
{
    /**
     * Returns a Cache Item representing the specified key.
     *
     * This method must always return a CacheItemInterface object, even in case of
     * a cache miss. It MUST NOT return null.
     *
     * @param string $key
     *   The key for which to return the corresponding Cache Item.
     *
     * @throws InvalidArgumentException
     *   If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
     *   MUST be thrown.
     *
     * @return CacheItemInterface
     *   The corresponding Cache Item.
     */
    public function getItem($key);

    /**
     * Returns a traversable set of cache items.
     *
     * @param array $keys
     * An indexed array of keys of items to retrieve.
     *
     * @throws InvalidArgumentException
     *   If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
     *   MUST be thrown.
     *
     * @return array|\Traversable
     *   A traversable collection of Cache Items keyed by the cache keys of
     *   each item. A Cache item will be returned for each key, even if that
     *   key is not found. However, if no keys are specified then an empty
     *   traversable MUST be returned instead.
     */
    public function getItems(array $keys = array());

    /**
     * Confirms if the cache contains specified cache item.
     *
     * Note: This method MAY avoid retrieving the cached value for performance reasons.
     * This could result in a race condition with CacheItemInterface::get(). To avoid
     * such situation use CacheItemInterface::isHit() instead.
     *
     * @param string $key
     *    The key for which to check existence.
     *
     * @throws InvalidArgumentException
     *   If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
     *   MUST be thrown.
     *
     * @return bool
     *  True if item exists in the cache, false otherwise.
     */
    public function hasItem($key);

    /**
     * Deletes all items in the pool.
     *
     * @return bool
     *   True if the pool was successfully cleared. False if there was an error.
     */
    public function clear();

    /**
     * Removes the item from the pool.
     *
     * @param string $key
     *   The key for which to delete
     *
     * @throws InvalidArgumentException
     *   If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
     *   MUST be thrown.
     *
     * @return bool
     *   True if the item was successfully removed. False if there was an error.
     */
    public function deleteItem($key);

    /**
     * Removes multiple items from the pool.
     *
     * @param array $keys
     *   An array of keys that should be removed from the pool.

     * @throws InvalidArgumentException
     *   If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
     *   MUST be thrown.
     *
     * @return bool
     *   True if the items were successfully removed. False if there was an error.
     */
    public function deleteItems(array $keys);

    /**
     * Persists a cache item immediately.
     *
     * @param CacheItemInterface $item
     *   The cache item to save.
     *
     * @return bool
     *   True if the item was successfully persisted. False if there was an error.
     */
    public function save(CacheItemInterface $item);

    /**
     * Sets a cache item to be persisted later.
     *
     * @param CacheItemInterface $item
     *   The cache item to save.
     *
     * @return bool
     *   False if the item could not be queued or if a commit was attempted and failed. True otherwise.
     */
    public function saveDeferred(CacheItemInterface $item);

    /**
     * Persists any deferred cache items.
     *
     * @return bool
     *   True if all not-yet-saved items were successfully saved or there were none. False otherwise.
     */
    public function commit();
}

##CacheException

This exception interface is intended for use when critical errors occur, including but not limited to cache setup such as connecting to a cache server or invalid credentials supplied.

Any exception thrown by an Implementing Library MUST implement this interface.

namespace Psr\Cache;

/**
 * Exception interface for all exceptions thrown by an Implementing Library.
 */
interface CacheException
{
}
InvalidArgumentException

namespace Psr\Cache;

/**
 * Exception interface for invalid cache arguments.
 *
 * Any time an invalid argument is passed into a method it must throw an
 * exception class which implements Psr\Cache\InvalidArgumentException.
 */
interface InvalidArgumentException extends CacheException
{
}