The cache component provides a Promise-based CacheInterface and an in-memory ArrayCache implementation of that

Overview

Cache

CI status

Async, Promise-based cache interface for ReactPHP.

The cache component provides a Promise-based CacheInterface and an in-memory ArrayCache implementation of that. This allows consumers to type hint against the interface and third parties to provide alternate implementations. This project is heavily inspired by PSR-16: Common Interface for Caching Libraries, but uses an interface more suited for async, non-blocking applications.

Table of Contents

Usage

CacheInterface

The CacheInterface describes the main interface of this component. This allows consumers to type hint against the interface and third parties to provide alternate implementations.

get()

The get(string $key, mixed $default = null): PromiseInterface method can be used to retrieve an item from the cache.

This method will resolve with the cached value on success or with the given $default value when no item can be found or when an error occurs. Similarly, an expired cache item (once the time-to-live is expired) is considered a cache miss.

$cache
    ->get('foo')
    ->then('var_dump');

This example fetches the value of the key foo and passes it to the var_dump function. You can use any of the composition provided by promises.

set()

The set(string $key, mixed $value, ?float $ttl = null): PromiseInterface method can be used to store an item in the cache.

This method will resolve with true on success or false when an error occurs. If the cache implementation has to go over the network to store it, it may take a while.

The optional $ttl parameter sets the maximum time-to-live in seconds for this cache item. If this parameter is omitted (or null), the item will stay in the cache for as long as the underlying implementation supports. Trying to access an expired cache item results in a cache miss, see also get().

$cache->set('foo', 'bar', 60);

This example eventually sets the value of the key foo to bar. If it already exists, it is overridden.

This interface does not enforce any particular TTL resolution, so special care may have to be taken if you rely on very high precision with millisecond accuracy or below. Cache implementations SHOULD work on a best effort basis and SHOULD provide at least second accuracy unless otherwise noted. Many existing cache implementations are known to provide microsecond or millisecond accuracy, but it's generally not recommended to rely on this high precision.

This interface suggests that cache implementations SHOULD use a monotonic time source if available. Given that a monotonic time source is only available as of PHP 7.3 by default, cache implementations MAY fall back to using wall-clock time. While this does not affect many common use cases, this is an important distinction for programs that rely on a high time precision or on systems that are subject to discontinuous time adjustments (time jumps). This means that if you store a cache item with a TTL of 30s and then adjust your system time forward by 20s, the cache item SHOULD still expire in 30s.

delete()

The delete(string $key): PromiseInterface method can be used to delete an item from the cache.

This method will resolve with true on success or false when an error occurs. When no item for $key is found in the cache, it also resolves to true. If the cache implementation has to go over the network to delete it, it may take a while.

$cache->delete('foo');

This example eventually deletes the key foo from the cache. As with set(), this may not happen instantly and a promise is returned to provide guarantees whether or not the item has been removed from cache.

getMultiple()

The getMultiple(string[] $keys, mixed $default = null): PromiseInterface method can be used to retrieve multiple cache items by their unique keys.

This method will resolve with an array of cached values on success or with the given $default value when an item can not be found or when an error occurs. Similarly, an expired cache item (once the time-to-live is expired) is considered a cache miss.

$cache->getMultiple(array('name', 'age'))->then(function (array $values) {
    $name = $values['name'] ?? 'User';
    $age = $values['age'] ?? 'n/a';

    echo $name . ' is ' . $age . PHP_EOL;
});

This example fetches the cache items for the name and age keys and prints some example output. You can use any of the composition provided by promises.

setMultiple()

The setMultiple(array $values, ?float $ttl = null): PromiseInterface method can be used to persist a set of key => value pairs in the cache, with an optional TTL.

This method will resolve with true on success or false when an error occurs. If the cache implementation has to go over the network to store it, it may take a while.

The optional $ttl parameter sets the maximum time-to-live in seconds for these cache items. If this parameter is omitted (or null), these items will stay in the cache for as long as the underlying implementation supports. Trying to access an expired cache items results in a cache miss, see also getMultiple().

$cache->setMultiple(array('foo' => 1, 'bar' => 2), 60);

This example eventually sets the list of values - the key foo to 1 value and the key bar to 2. If some of the keys already exist, they are overridden.

deleteMultiple()

The setMultiple(string[] $keys): PromiseInterface method can be used to delete multiple cache items in a single operation.

This method will resolve with true on success or false when an error occurs. When no items for $keys are found in the cache, it also resolves to true. If the cache implementation has to go over the network to delete it, it may take a while.

$cache->deleteMultiple(array('foo', 'bar, 'baz'));

This example eventually deletes keys foo, bar and baz from the cache. As with setMultiple(), this may not happen instantly and a promise is returned to provide guarantees whether or not the item has been removed from cache.

clear()

The clear(): PromiseInterface method can be used to wipe clean the entire cache.

This method will resolve with true on success or false when an error occurs. If the cache implementation has to go over the network to delete it, it may take a while.

$cache->clear();

This example eventually deletes all keys from the cache. As with deleteMultiple(), this may not happen instantly and a promise is returned to provide guarantees whether or not all the items have been removed from cache.

has()

The has(string $key): PromiseInterface method can be used to determine whether an item is present in the cache.

This method will resolve with true on success or false when no item can be found or when an error occurs. Similarly, an expired cache item (once the time-to-live is expired) is considered a cache miss.

$cache
    ->has('foo')
    ->then('var_dump');

This example checks if the value of the key foo is set in the cache and passes the result to the var_dump function. You can use any of the composition provided by promises.

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.

ArrayCache

The ArrayCache provides an in-memory implementation of the CacheInterface.

$cache = new ArrayCache();

$cache->set('foo', 'bar');

Its constructor accepts an optional ?int $limit parameter to limit the maximum number of entries to store in the LRU cache. If you add more entries to this instance, it will automatically take care of removing the one that was least recently used (LRU).

For example, this snippet will overwrite the first value and only store the last two entries:

$cache = new ArrayCache(2);

$cache->set('foo', '1');
$cache->set('bar', '2');
$cache->set('baz', '3');

This cache implementation is known to rely on wall-clock time to schedule future cache expiration times when using any version before PHP 7.3, because a monotonic time source is only available as of PHP 7.3 (hrtime()). While this does not affect many common use cases, this is an important distinction for programs that rely on a high time precision or on systems that are subject to discontinuous time adjustments (time jumps). This means that if you store a cache item with a TTL of 30s on PHP < 7.3 and then adjust your system time forward by 20s, the cache item may expire in 10s. See also set() for more details.

Common usage

Fallback get

A common use case of caches is to attempt fetching a cached value and as a fallback retrieve it from the original data source if not found. Here is an example of that:

$cache
    ->get('foo')
    ->then(function ($result) {
        if ($result === null) {
            return getFooFromDb();
        }
        
        return $result;
    })
    ->then('var_dump');

First an attempt is made to retrieve the value of foo. A callback function is registered that will call getFooFromDb when the resulting value is null. getFooFromDb is a function (can be any PHP callable) that will be called if the key does not exist in the cache.

getFooFromDb can handle the missing key by returning a promise for the actual value from the database (or any other data source). As a result, this chain will correctly fall back, and provide the value in both cases.

Fallback get and set

To expand on the fallback get example, often you want to set the value on the cache after fetching it from the data source.

$cache
    ->get('foo')
    ->then(function ($result) {
        if ($result === null) {
            return $this->getAndCacheFooFromDb();
        }
        
        return $result;
    })
    ->then('var_dump');

public function getAndCacheFooFromDb()
{
    return $this->db
        ->get('foo')
        ->then(array($this, 'cacheFooFromDb'));
}

public function cacheFooFromDb($foo)
{
    $this->cache->set('foo', $foo);

    return $foo;
}

By using chaining you can easily conditionally cache the value if it is fetched from the database.

Install

The recommended way to install this library is through Composer. New to Composer?

This project follows SemVer. This will install the latest supported version:

$ composer require react/cache:^1.1

See also the CHANGELOG for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP extensions and supports running on legacy PHP 5.3 through current PHP 8+ and HHVM. It's highly recommended to use PHP 7+ for this project.

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

$ composer install

To run the test suite, go to the project root and run:

$ php vendor/bin/phpunit

License

MIT, see LICENSE file.

Comments
  • Return Promise for set and remove

    Return Promise for set and remove

    This PR builds on #16 by resolving merge conflicts and adding more documentation in the cache interface plus adding documentation to the readme.

    Supersedes / closes #16

    new feature BC break maintenance 
    opened by WyriHaximus 15
  • Semantics of get() on cache miss

    Semantics of get() on cache miss

    Currently, get() returns a rejected promise on a cache miss. Since rejection is the asynchronous equivalent of throwing an exception in synchronous code, it behaves like

    public function get($key)
    {
        if (!isset($this->data[$key])) {
            throw new \Exception()
        }
    
        return $this->data[$key];
    }
    

    Is this the intended behavior?

    new feature BC break 
    opened by jsor 8
  • Support hasMultiple

    Support hasMultiple

    I know it's not part of PSR-16 and sadly I don't know why because some cache controller could benefit from this function.

    I would expect that's for a simple cache like ArrayCache it would be a simple loop on all values. The same using all($getArray); would be an overkill and I would expect an performance impact.

    If no plans to add it I'm happy too.

    new feature question 
    opened by HLeithner 5
  • [RFC] Prepare stable release

    [RFC] Prepare stable release

    We should look into providing a stable (in the sense of SemVer) release for this component.

    From looking at the version history it looks like the very first tagged release could in fact already have been a v1.0.0.

    This ticket aims to serve as an RFC.

    maintenance 
    opened by clue 4
  • [RFC] Support TTL

    [RFC] Support TTL

    I've been thinking about how we can improve caching and what I would really like to see is TTL support in cache adapters. With that the DNS component only store a message contents in the cache and gives it a TTL. The DNS component also doesn't have to do the GC as that becomes the responsibility of the adapter. In cache of a redis adapter redis can take care of that. But for the array cache another mechanism has to be devised.

    new feature help wanted 
    opened by WyriHaximus 3
  • Use high-resolution timer for cache TTL on PHP 7.3+

    Use high-resolution timer for cache TTL on PHP 7.3+

    This project suggests that cache implementations SHOULD use a monotonic time source if available. Given that a monotonic time source is only available as of PHP 7.3 by default, event loop implementations MAY fall back to using wall-clock time. http://php.net/manual/en/function.hrtime.php

    Builds on top of https://github.com/reactphp/event-loop/pull/182 and https://github.com/reactphp/event-loop/pull/130

    new feature 
    opened by clue 2
  • Rename remove() to delete() for consistency with PSR-16

    Rename remove() to delete() for consistency with PSR-16

    This simple PR renames the existing remove() method to delete() for consistency with PSR-6 and PSR-16. It also adds some documentation to be in line with #16 and #29, but the behavior is otherwise left unchanged.

    // old
    $cache->remove('foo');
    
    // new
    $cache->delete('foo');
    

    Empirical evidence suggests that this method is rarely used and this release includes a number of BC breaks that aim at making this interface act more like a standard PSR-16 cache, so I figured it makes sense to rename this as part of this release.

    BC break easy pick 
    opened by clue 2
  • Cache miss resolves with null value

    Cache miss resolves with null value

    As discussed in #13, a failing get should resolve with null instead of rejecting.

    To do:

    • [X] Updated interface
    • [x] Updated ArrayCache
    • [x] Updated Readme

    Implements / closes #13

    BC break maintenance easy pick help wanted 
    opened by WyriHaximus 2
  • Limit cache size for ArrayCache

    Limit cache size for ArrayCache

    The ArrayCache keeps growing and growing when new data is added to it. We should probably add an optional parameter to limit the cache size and implement a simple LRU algorithm to remove "old" entries.

    new feature help wanted 
    opened by clue 2
  • Add cache expiration support (TTL)

    Add cache expiration support (TTL)

    This PR adds support for cache expiry (TTL). This is a new feature for most consumers, but this is also a BC break because it adds a new parameter to the CacheInterface::set($name, $value, $ttl = null) signature.

    As its name implies, the ArrayCache uses an array to store the optional TTL and will yield a cache miss when a cache item is expired.

    Builds on top of #28, thank you @WyriHaximus for the initial version! I've squashed the original version to a single commit to preserve authorship. Unlike the initial version, this updated version uses an array for significantly faster operation (heavily inspired by https://github.com/reactphp/event-loop/pull/164).

    Supersedes / closes #28 Resolves / closes #11

    new feature BC break 
    opened by clue 1
  • [RFC] CacheInterface documentation

    [RFC] CacheInterface documentation

    The CacheInterface is currently lacking documentation on the expected workings of a cache implementing CacheInterface. This PR aims to add that, and will require followup PR's to update ArrayCache and the readme.

    Supersedes / closes #16 Implements / closes #13

    maintenance easy pick help wanted 
    opened by WyriHaximus 1
  • [1.x] Set up PHPStan on GitHub Actions

    [1.x] Set up PHPStan on GitHub Actions

    This PR sets up PHPStan to run on GitHub Actions, as discussed in discussions#469.

    Overview

    • [x] Sets up PHPStan to run on GitHub Actions on PHP 8.1 only
    • [x] Configures PHPStan to run the analysis on the src and tests folders
    • [x] Generates the baseline so that static analysis passes immediately

    Baseline

    Because this PR aims to set up PHPStan and not address the errors it reports, I've generated a baseline to make the pipeline succeed. We'll then be able to incrementally fix the problems in future PRs.

    opened by nhedger 0
Releases(v1.2.0)
  • v1.2.0(Nov 30, 2022)

    • Feature: Support PHP 8.1 and PHP 8.2. (#47 by @SimonFrings and #52 by @WyriHaximus)

    • Minor documentation improvements. (#48 by @SimonFrings and #51 by @nhedger)

    • Update test suite and use GitHub actions for continuous integration (CI). (#45 and #49 by @SimonFrings and #54 by @clue)

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Feb 2, 2021)

  • v1.1.0(Sep 18, 2020)

    • Feature: Forward compatibility with react/promise 3. (#39 by @WyriHaximus)

    • Add .gitattributes to exclude dev files from exports. (#40 by @reedy)

    • Improve test suite, update to support PHP 8 and PHPUnit 9.3. (#41 and #43 by @SimonFrings and #42 by @WyriHaximus)

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jul 11, 2019)

    • First stable LTS release, now following SemVer. We'd like to emphasize that this component is production ready and battle-tested. We plan to support all long-term support (LTS) releases for at least 24 months, so you have a rock-solid foundation to build on top of.

    Contains no other changes, so it's actually fully compatible with the v0.6.0 release.

    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Jul 4, 2019)

    • Feature / BC break: Add support for getMultiple(), setMultiple(), deleteMultiple(), clear() and has() supporting multiple cache items (inspired by PSR-16). (#32 by @krlv and #37 by @clue)

    • Documentation for TTL precision with millisecond accuracy or below and use high-resolution timer for cache TTL on PHP 7.3+. (#35 and #38 by @clue)

    • Improve API documentation and allow legacy HHVM to fail in Travis CI config. (#34 and #36 by @clue)

    • Prefix all global functions calls with \ to skip the look up and resolve process and go straight to the global function. (#31 by @WyriHaximus)

    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Jun 25, 2018)

    • Improve documentation by describing what is expected of a class implementing CacheInterface. (#21, #22, #23, #27 by @WyriHaximus)

    • Implemented (optional) Least Recently Used (LRU) cache algorithm for ArrayCache. (#26 by @clue)

    • Added support for cache expiration (TTL). (#29 by @clue and @WyriHaximus)

    • Renamed remove to delete making it more in line with PSR-16. (#30 by @clue)

    Source code(tar.gz)
    Source code(zip)
  • v0.4.2(Dec 20, 2017)

    • Improve documentation with usage and installation instructions (#10 by @clue)

    • Improve test suite by adding PHPUnit to require-dev and add forward compatibility with PHPUnit 5 and PHPUnit 6 and sanitize Composer autoload paths (#14 by @shaunbramley and #12 and #18 by @clue)

    Source code(tar.gz)
    Source code(zip)
  • v0.4.1(Feb 25, 2016)

    • Repository maintenance, split off from main repo, improve test suite and documentation
    • First class support for PHP7 and HHVM (#9 by @clue)
    • Adjust compatibility to 5.3 (#7 by @clue)
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Feb 25, 2016)

    • BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
    • BC break: Update to React/Promise 2.0
    • Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(Feb 25, 2016)

  • v0.3.0(Feb 25, 2016)

  • v0.2.6(Feb 25, 2016)

Owner
ReactPHP
Event-driven, non-blocking I/O with PHP.
ReactPHP
A thin PSR-6 cache wrapper with a generic interface to various caching backends emphasising cache tagging and indexing.

Apix Cache, cache-tagging for PHP Apix Cache is a generic and thin cache wrapper with a PSR-6 interface to various caching backends and emphasising ca

Apix 111 Nov 26, 2022
LaraCache is an ORM based package for Laravel to create, update and manage cache items based on model queries

LaraCache Using this package, you can cache your heavy and most used queries. All you have to do is to define the CacheEntity objects in the model and

Mostafa Zeinivand 202 Dec 19, 2022
Doctrine Cache component

Doctrine Cache Cache component extracted from the Doctrine Common project. Documentation This library is deprecated and will no longer receive bug fix

Doctrine 7.6k Jan 3, 2023
LRU Cache implementation in PHP

PHP LRU Cache implementation Intro WTF is a LRU Cache? LRU stands for Least Recently Used. It's a type of cache that usually has a fixed capacity and

Rogério Vicente 61 Jun 23, 2022
PSR-6 cache implementation adapting a given PSR-16 instance

PSR-6 cache implementation adapting PSR-16 This package provides a PSR-6 cache instance when you only have a PSR-16 cache at hand. As PSR-6 is more fe

null 1 Oct 15, 2021
Distributed PSR-16 cache implementation for PHP 6 that uses browser cookies to store data

cookiecache Cache beyond the edge with cookies! This library provides a distributed PSR-16 compatible cache implementation for PHP 6 that uses browser

Colin O'Dell 8 Apr 19, 2022
PHP cache implementation supporting memcached

php cache implementation (PSR-6 and PSR-16) Support for memcached and APCu is included. Memcached $memcached = new Memcached(); $memcached->addServer(

Michael Bretterklieber 1 Aug 11, 2022
PHP cache library, with adapters for e.g. Memcached, Redis, Couchbase, APC(u), SQL and additional capabilities (e.g. transactions, stampede protection) built on top.

Donate/Support: Documentation: https://www.scrapbook.cash - API reference: https://docs.scrapbook.cash Table of contents Installation & usage Adapters

Matthias Mullie 295 Nov 28, 2022
A simple cache library. Implements different adapters that you can use and change easily by a manager or similar.

Desarolla2 Cache A simple cache library, implementing the PSR-16 standard using immutable objects. Caching is typically used throughout an applicatito

Daniel González 129 Nov 20, 2022
A library providing platform-specific user directory paths, such as config and cache

Phirs A library providing platform-specific user directory paths, such as config and cache. Inspired by dirs-rs.

Mohammad Amin Chitgarha 7 Mar 1, 2022
A simple cache library. Implements different adapters that you can use and change easily by a manager or similar.

Desarolla2 Cache A simple cache library, implementing the PSR-16 standard using immutable objects. Caching is typically used throughout an applicatito

Daniel González 129 Nov 20, 2022
The place to keep your cache.

Stash - A PHP Caching Library Stash makes it easy to speed up your code by caching the results of expensive functions or code. Certain actions, like d

Tedious Developments 944 Jan 4, 2023
Cache slam defense using a semaphore to prevent dogpile effect.

metaphore PHP cache slam defense using a semaphore to prevent dogpile effect (aka clobbering updates, stampending herd or Slashdot effect). Problem: t

Przemek Sobstel 102 Sep 28, 2022
:zap: Simple Cache Abstraction Layer for PHP

⚡ Simple Cache Class This is a simple Cache Abstraction Layer for PHP >= 7.0 that provides a simple interaction with your cache-server. You can define

Lars Moelleken 27 Dec 8, 2022
Simple cache abstraction layer implementing PSR-16

sabre/cache This repository is a simple abstraction layer for key-value caches. It implements PSR-16. If you need a super-simple way to support PSR-16

sabre.io 48 Sep 9, 2022
More Than Just a Cache: Redis Data Structures

More Than Just a Cache: Redis Data Structures Redis is a popular key-value store, commonly used as a cache or message broker service. However, it can

Andy Snell 2 Oct 16, 2021
Simple cache

Simple cache

Róbert Kelčák 3 Dec 17, 2022
Elephant - a highly performant PHP Cache Driver for Kirby 3

?? Kirby3 PHP Cache-Driver Elephant - a highly performant PHP Cache Driver for Kirby 3 Commerical Usage Support open source! This plugin is free but i

Bruno Meilick 11 Apr 6, 2022