「PSR 规范」PSR-6 缓存接口规范

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

    目标

    本 PSR 的目标是:创建一套通用的接口规范,能够让开发人员整合到现有框架和系统,而不需要去
    开发框架专属的适配器类。

    为了避免歧义,文档大量使用了「能愿动词」,对应的解释如下:

    • :绝对,严格遵循,请照做,无条件遵守;
    • 一定不可 (MUST NOT):禁令,严令禁止;
    • 应该 (SHOULD) :强烈建议这样做,但是不强求;
    • 不该 (SHOULD NOT):强烈不建议这样做,但是不强求;
    • 可以 (MAY)可选 (OPTIONAL) :选择性高一点,在这个文档内,此词语使用较少;

    定义

    • 调用类库 (Calling Library) - 调用者,使用缓存服务的类库,这个类库调用缓存服务,调用的
      是此缓存接口规范的具体「实现类库」,调用者不需要知道任何「缓存服务」的具体实现。

    • 实现类库 (Implementing Library) - 此类库是对「缓存接口规范」的具体实现,封装起来的缓存服务,供「调用类库」使用。实现类库 必须 提供 PHP 类来实现
      Cache\CacheItemPoolInterfaceCache\CacheItemInterface 接口。
      实现类库 必须 支持最小的如下描述的 TTL 功能,秒级别的精准度。

    • 过期时间 (Expiration) - 定义准确的过期时间点,一般为缓存存储发生的时间点加上 TTL 时
      间值,也可以指定一个 DateTime 对象。

      假如一个缓存项的 TTL 设置为 300 秒,保存于 100 ,那么缓存项的过期时间为 1:35:00。

    • 键 (KEY) - 长度大于 1 的字串,用作缓存项在缓存系统里的唯一标识符。实现类库
      必须 支持「键」规则 , a-z, 0-9, _, 和 . 任何顺序的 UTF-8 编码,长度
      小于 64 位。实现类库 可以 支持更多的编码或者更长的长度,不过 必须 支持至少以上指定
      的编码和长度。实现类库可自行实现对「键」的转义,但是 必须 保证能够无损的返回「键」字串。以下
      的字串作为系统保留: {}()/\@:一定不可 作为「键」的命名支持。

    • 命中 (Hit) - 一个缓存的命中,指的是当调用类库使用「键」在请求一个缓存项的时候,在缓存
      池里能找到对应的缓存项,并且此缓存项还未过期,并且此数据不会因为任何原因出现错误。调用类
      应该 确保先验证下 isHit() 有命中后才调用 get() 获取数据。

    • 未命中 (Miss) - 一个缓存未命中,是完全的上面描述的「命中」的相反。指的是当调用类库使用「键」在请求一个缓存项的时候,在缓存池里未能找到对应的缓存项,或者此缓存项已经过期,或者此数据因为任何原因出现错误。一个过期的缓存项,必须 被当做 未命中 来对待。

    • 延迟 (Deferred) - 一个延迟的缓存,指的是这个缓存项可能不会立刻被存储到物理缓存池里。一个
      缓存池对象 可以 对一个指定延迟的缓存项进行延迟存储,这样做的好处是可以利用一些缓存服务器提供
      的批量插入功能。缓存池 必须 能对所有延迟缓存最终能持久化,并且不会丢失。可以 在调用类库还未发起保存请求之前就做持久化。当调用类库调用 commit() 方法时,所有的延迟缓存都 必须
      做持久化。实现类库 可以 自行决定使用什么逻辑来触发数据持久化,如对象的 析构方法 (destructor) 内、调用 时持久化、倒计时保存或者触及最大数量时保存等。当请求一个延迟
      缓存项时,必须 返回一个延迟,未持久化的缓存项对象。

    实现类库 必须 支持所有的可序列化的 PHP 数据类型,包含:

    • 字符串 - 任何大小的 PHP 兼容字符串
    • 整数 - PHP 支持的低于 64 位的有符号整数值
    • 浮点数 - 所有的有符号浮点数
    • 布尔 - true 和 false.
    • Null - null
    • 对象(Object) - 所有的支持无损序列化和反序列化的对象,如:$o == unserialize(serialize($o)) 。对象 可以
      使用 PHP 的 Serializable 接口,__sleep() 或者 __wakeup() 魔术方法,或者在合适的情况下,使用其他类似的语言特性。

    所有存进实现类库的数据,都 必须 能做到原封不动的取出。连类型也 必须 是完全一致,如果
    存进缓存的是字符串 5,取出来的却是整数值 5 的话,可以算作严重的错误。实现类库 可以 使用 PHP 的「serialize()/unserialize() 方法」作为底层实现,不过不强迫这样做。对于他们的兼容性,以能支持所有数据类型作为基准线。

    实在无法「完整取出」存入的数据的话,实现类库 必须 把「缓存丢失」标示作为返回,而不是损坏了的数据。

    主要概念

    缓存池包含缓存系统里所有缓存数据的集合。缓存池逻辑上是所有缓存项存储的仓库,所有存储进去的数据,
    都能从缓存池里取出来,所有的对缓存的操作,都发生在缓存池子里。

    缓存项 Items

    一条缓存项在缓存池里代表了一对「键/值」对应的数据,「键」被视为每一个缓存项主键,是缓存项的
    唯一标识符,必须 是不可变更的,当然,「值」可以 任意变更。

    缓存系统里的错误 一定不可 导致应用程序故障,所以,实现类库 一定不可 抛出任何除了
    此接口规范定义的以外的异常,并且 必须 捕捉包括底层存储驱动抛出的异常,不让其冒泡至超
    出缓存系统内。

    实现类库 应该 对此类错误进行记录,或者以任何形式通知管理员。

    调用类库发起删除缓存项的请求,或者清空整个缓冲池子的请求,「键」不存在的话 必须 不能
    当成是有错误发生。后置条件是一样的,如果取数据时,「键」不存在的话 必须 不能当成是有错误发生

    接口

    CacheItemInterface 定义了缓存系统里的一个缓存项。每一个缓存项 必须 有一个「键」与之相
    关联,此「键」通常是通过 Cache\CacheItemPoolInterface 来设置。

    Cache\CacheItemInterface 对象把缓存项的存储进行了封装,每一个 Cache\CacheItemInterface 由一个 Cache\CacheItemPoolInterface 对象生成,CacheItemPoolInterface 负责一些必须的设置,并且给对象设置具有 唯一性 的「键」。

    Cache\CacheItemInterface 对象 必须 能够存储和取出任何类型的,在「数据」章节定义的 PHP 数值。

    调用类库 一定不可 擅自初始化「CacheItemInterface」对象,「缓存项」只能使用「CacheItemPoolInterface」对象的 getItem() 方法来获取。调用类库 一定不可 假设
    由一个实现类库创建的「缓存项」能被另一个实现类库完全兼容。

    CacheItemPoolInterface

    Cache\CacheItemPoolInterface 的主要目的是从调用类库接收「键」,然后返回对应的 Cache\CacheItemInterface 对象。

    此接口也是作为主要的,与整个缓存集合交互的方式。所有的配置和初始化由实现类库自行实现。

    所有的实现类库抛出的异常都 必须 实现此接口。

    InvalidArgumentException