PSR-16: Common Interface for Caching Libraries

Common Interface for Caching Libraries

This document describes a simple yet extensible interface for a cache item and
a cache driver.

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”,
“SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be
interpreted as described in RFC 2119.

The final implementations MAY decorate the objects with more
functionality than the one proposed but they MUST implement the indicated
interfaces/functionality first.

1. Specification

1.1 Introduction

Caching is a common way to improve the performance of any project, making
caching libraries one of the most common features of many frameworks and
libraries. Interoperability at this level means libraries can drop their
own caching implementations and easily rely on the one given to them by the
framework, or another dedicated cache library.

PSR-6 solves this problem already, but in a rather formal and verbose way for
what the most simple use cases need. This simpler approach aims to build a
standardized streamlined interface for common cases. It is independent of
PSR-6 but has been designed to make compatibility with PSR-6 as straightforward
as possible.

1.2 Definitions

Definitions for Calling Library, Implementing Library, TTL, Expiration and Key
are copied from PSR-6 as the same assumptions are true.

  • Calling Library - The library or code that actually needs the cache
    services. This library will utilize caching services that implement this
    standard’s interfaces, but will otherwise have no knowledge of the
    implementation of those caching services.

  • Implementing Library - This library is responsible for implementing
    this standard in order to provide caching services to any Calling Library. The
    Implementing Library MUST provide a class implementing the Psr\SimpleCache\CacheInterface interface.
    Implementing Libraries MUST support at minimum TTL functionality as described
    below with whole-second granularity.

  • TTL - The Time To Live (TTL) of an item is the amount of time between
    when that item is stored and it is considered stale. The TTL is normally defined
    by an integer representing time in seconds, or a DateInterval object.

  • Expiration - The actual time when an item is set to go stale. This is
    calculated by adding the TTL to the time when an object is stored.

    An item with a 300 second TTL stored at 1:30:00 will have an expiration of 1:35:00.

    Implementing Libraries MAY expire an item before its requested Expiration Time,
    but MUST treat an item as expired once its Expiration Time is reached. If a calling
    library asks for an item to be saved but does not specify an expiration time, or
    specifies a null expiration time or TTL, an Implementing Library MAY use a configured
    default duration. If no default duration has been set, the Implementing Library
    MUST interpret that as a request to cache the item forever, or for as long as the
    underlying implementation supports.

    If a negative or zero TTL is provided, the item MUST be deleted from the cache
    if it exists, as it is expired already.

  • Key - A string of at least one character that uniquely identifies a
    cached item. Implementing libraries MUST support keys consisting of the
    characters A-Z, a-z, 0-9, _, and . in any order in UTF-8 encoding and a
    length of up to 64 characters. Implementing libraries MAY support additional
    characters and encodings or longer lengths, but must support at least that
    minimum. Libraries are responsible for their own escaping of key strings
    as appropriate, but MUST be able to return the original unmodified key string.
    The following characters are reserved for future extensions and MUST NOT be
    supported by implementing libraries: {}()/\@:

  • Cache - An object that implements the Psr\SimpleCache\CacheInterface interface.

  • Cache Misses - A cache miss will return null and therefore detecting
    if one stored null is not possible. This is the main deviation from PSR-6’s
    assumptions.

1.3 Cache

Implementations MAY provide a mechanism for a user to specify a default TTL
if one is not specified for a specific cache item. If no user-specified default
is provided implementations MUST default to the maximum legal value allowed by
the underlying implementation. If the underlying implementation does not
support TTL, the user-specified TTL MUST be silently ignored.

1.4 Data

Implementing libraries MUST support all serializable PHP data types, including:

  • Strings - Character strings of arbitrary size in any PHP-compatible encoding.
  • Integers - All integers of any size supported by PHP, up to 64-bit signed.
  • Floats - All signed floating point values.
  • Boolean - True and False.
  • Null - The null value (although it will not be distinguishable from a
    cache miss when reading it back out).
  • Arrays - Indexed, associative and multidimensional arrays of arbitrary depth.
  • Object - Any object that supports lossless serialization and
    deserialization such that $o == unserialize(serialize($o)). Objects MAY
    leverage PHP’s Serializable interface, __sleep() or __wakeup() magic methods,
    or similar language functionality if appropriate.

All data passed into the Implementing Library MUST be returned exactly as
passed. That includes the variable type. That is, it is an error to return
(string) 5 if (int) 5 was the value saved. Implementing Libraries MAY use PHP’s
serialize()/unserialize() functions internally but are not required to do so.
Compatibility with them is simply used as a baseline for acceptable object values.

If it is not possible to return the exact saved value for any reason, implementing
libraries MUST respond with a cache miss rather than corrupted data.

2. Interfaces

2.1 CacheInterface

The cache interface defines the most basic operations on a collection of cache-entries, which
entails basic reading, writing and deleting individual cache items.

In addition it has methods for dealing with multiple sets of cache entries such as writing, reading or
deleting multiple cache entries at a time. This is useful when you have lots of cache reads/writes
to perform, and lets you perform your operations in a single call to the cache server cutting down latency
times dramatically.

An instance of CacheInterface corresponds to a single collection of cache items with a single key namespace,
and is equivalent to a “Pool” in PSR-6. Different CacheInterface instances MAY be backed by the same
datastore, but MUST be logically independent.

<?php

namespace Psr\SimpleCache;

interface CacheInterface
{
    /**
     * Fetches a value from the cache.
     *
     * @param string $key     The unique key of this item in the cache.
     * @param mixed  $default Default value to return if the key does not exist.
     *
     * @return mixed The value of the item from the cache, or $default in case of cache miss.
     *
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *   MUST be thrown if the $key string is not a legal value.
     */
    public function get($key, $default = null);

    /**
     * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.
     *
     * @param string                 $key   The key of the item to store.
     * @param mixed                  $value The value of the item to store, must be serializable.
     * @param null|int|\DateInterval $ttl   Optional. The TTL value of this item. If no value is sent and
     *                                      the driver supports TTL then the library may set a default value
     *                                      for it or let the driver take care of that.
     *
     * @return bool True on success and false on failure.
     *
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *   MUST be thrown if the $key string is not a legal value.
     */
    public function set($key, $value, $ttl = null);

    /**
     * Delete an item from the cache by its unique key.
     *
     * @param string $key The unique cache key of the item to delete.
     *
     * @return bool True if the item was successfully removed. False if there was an error.
     *
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *   MUST be thrown if the $key string is not a legal value.
     */
    public function delete($key);

    /**
     * Wipes clean the entire cache's keys.
     *
     * @return bool True on success and false on failure.
     */
    public function clear();

    /**
     * Obtains multiple cache items by their unique keys.
     *
     * @param iterable $keys    A list of keys that can obtained in a single operation.
     * @param mixed    $default Default value to return for keys that do not exist.
     *
     * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.
     *
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *   MUST be thrown if $keys is neither an array nor a Traversable,
     *   or if any of the $keys are not a legal value.
     */
    public function getMultiple($keys, $default = null);

    /**
     * Persists a set of key => value pairs in the cache, with an optional TTL.
     *
     * @param iterable               $values A list of key => value pairs for a multiple-set operation.
     * @param null|int|\DateInterval $ttl    Optional. The TTL value of this item. If no value is sent and
     *                                       the driver supports TTL then the library may set a default value
     *                                       for it or let the driver take care of that.
     *
     * @return bool True on success and false on failure.
     *
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *   MUST be thrown if $values is neither an array nor a Traversable,
     *   or if any of the $values are not a legal value.
     */
    public function setMultiple($values, $ttl = null);

    /**
     * Deletes multiple cache items in a single operation.
     *
     * @param iterable $keys A list of string-based keys to be deleted.
     *
     * @return bool True if the items were successfully removed. False if there was an error.
     *
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *   MUST be thrown if $keys is neither an array nor a Traversable,
     *   or if any of the $keys are not a legal value.
     */
    public function deleteMultiple($keys);

    /**
     * Determines whether an item is present in the cache.
     *
     * NOTE: It is recommended that has() is only to be used for cache warming type purposes
     * and not to be used within your live applications operations for get/set, as this method
     * is subject to a race condition where your has() will return true and immediately after,
     * another script can remove it making the state of your app out of date.
     *
     * @param string $key The cache item key.
     *
     * @return bool
     *
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *   MUST be thrown if the $key string is not a legal value.
     */
    public function has($key);
}

2.2 CacheException


<?php

namespace Psr\SimpleCache;

/**
 * Interface used for all types of exceptions thrown by the implementing library.
 */
interface CacheException
{
}

2.3 InvalidArgumentException

<?php

namespace Psr\SimpleCache;

/**
 * Exception interface for invalid cache arguments.
 *
 * When an invalid argument is passed it must throw an exception which implements
 * this interface
 */
interface InvalidArgumentException extends CacheException
{
}