thomas-institut / datacache
Cache abstraction and basic implementation
Requires
- php: >=8.3
Requires (Dev)
- phpunit/phpunit: ^12.0
- squizlabs/php_codesniffer: ^3.12
README
This package provides an interface to a cache that can store strings. It also provides three simple, yet effective implementations.
Implementations MUST pass all tests in the included DataCacheReferenceTest
DataCache Interface
class MyDataCache implements DataCache { // ... } $cache = new MyDataCache(...);
To cache a string with the cache's default TTL:
$cache->set('someKey', 'someValue');
There are no restrictions on the characters that can be used as a key or value: any character is allowed (including non-printable ones) and there is no set maximum length.
Implementations MUST support arbitrary characters in keys and values but MAY impose some limits to key and value lengths. Implementations MUST support maximum key lengths of at least 2048 characters and maximum value lengths of at least 32 megabytes.
Implementations decide what is the default TTL when the user has not specified one. The default TTL can be set at any time with:
$cache->setDefaultTtl($newDefaultTtl);
TTLs are given in seconds. A TTL of 0 seconds means that items will not expire.
If a negative TTL is given to the setDefaultTtl
method, no changes will be made
to the current default TTL.
The default TTL can be overridden when setting a value:
$cache->set('someKey', 'someValue', $customTtl);
where $customTtl
is given in seconds. A TTL
equal to zero instructs the cache to never expire the item, while a negative
TTL is ignored (and the default TTL will be used).
The value of a cached item can be retrieved with:
$value = $cache->get('someKey');
If the item is not in the cache, the get
method will throw an ItemNotInCacheException
.
To check if an item is in the case without necessarily retrieving it, use the following convenience method:
$exists = $cache->isInCache('someKey');
However, implementations may still have to retrieve the item to test for existence, so
it cannot be generally assumed that the isInCache
method is more efficient.
Some implementations may be able to report the remaining TTL for an item:
$remainingTtl = $cache->getRemainingTtl('someKey');
If the cache does not support reporting remaining TTLs, this method returns -1. Otherwise, it returns the number of seconds until the item's expiration or 0 if the item will never expire.
To delete an item:
$cache->delete('someKey');
The delete method returns silently if the item is not in the cache.
All the items in the cache can be deleted at once with the flush method:
$cache->flush();
Depending on the implementation, a cache flush may delete everything in the cache, including items that were stored in the same underlying storage or service by other DataCache instances or by any other means. The only mandatory behaviour is that all items set by the cache instance must not be accessible after a flush.
Some implementations may also be able to clean the cache by releasing memory or storage space for items that are already expired:
$cache->clean();
If the implementation does not support cleaning or if manual cleaning is not available for the cache, the clean method will return silently and nothing will happen.
InMemoryDataCache
InMemoryDataCache
is a DataCache
implementation that uses a PHP array to
store item values.
The constructor does not have any parameters:
$cache = new InMemoryDataCache();
This cache supports arbitrary length keys and values, can report remaining TTLs and
will only remove expired items from the underlying PHP array when explicitly deleted or
when the clean
or flush
methods are called.
When the instance is destroyed, all cached items will be destroyed as well.
DirectoryDataCache
DirectoryDataCache
is a DataCache
that stores each individual item's value
in a file in a given directory. That is, every item generates one separate file that
contains the value of the item. As such, the cache's content will persist after
instances are destroyed, and items can be deleted manually by simply deleting
their corresponding files.
$cache = new DirectoryDataCache('/path/to/directory', $cacheName);
$cacheName
is a string that identifies the cache. It is used as a filename prefix
for the files generated by the cache. This allows to have multiple independent caches
in the same directory.
The file name for a cached item has the following form:
$directoryPath . '/' . $cacheName . $sep . $keyOrHash . $sep . $exp . '.' . $ext
where $sep
is a separator character (by default '-'
) and $ext
is a
file extension (by default 'txt'
).
By default, $keyOrHash
is the item's key if the key does not contain the separator
nor any character that the file system does not allow in file name. Otherwise,
a hash of the key will be used instead.
$exp
is the Unix timestamp after which the item is no longer valid.
The constructor has three more optional parameters to control file names:
- the file extension to use for all files (default
'txt'
). It can be empty. - the character to use as field separator in file name (default
'-'
). The characters*
and/
cannot be used as separators. If the file extension is not empty, the dot cannot be used either. - a boolean flag that instructs the cache to ALWAYS use the hash of an item's key in the file
name (default
false
).
DirectoryDataCache
supports arbitrary length keys and values, does NOT report remaining
TTLs and will only delete files from disk when items are explicitly deleted or when the
clean
or flush
methods are called.
MultiCacheDataCache
MultiCacheDataCache
is a DataCache
that aggregates a list of DataCache
instances.
When an item is stored, it is stored in all caches and when it is deleted it is deleted
from all caches as well. However, when an item is retrieved, it is only retrieved from
the first cache in the list that has it.
The intended use of this cache is setting up faster caches in the first positions in the list and slower, perhaps persistent caches, in the latter positions. Reads will normally be handled by the faster caches, while the slower, persistent caches are used as backup.
The constructor requires an array of cache instances or callables that return
a cache instance, an optional array of key prefixes to attach to keys in the corresponding
caches and an optional boolean flag that when true
, instructs the cache to use
an InMemoryDataCache
when a cache callable fails (by default this flag is false
)
$cache = new MultiCacheDataCache( [ $cache1, $callable2, $cache3 ...]); $cache2 = new MultiCacheDataCache( [ $cache1, $callable2, ...], [ 'prefix1', 'prefix2', ...], true);
CacheAware Interface
CacheAware
is an interface that provides common functions
that allow clients to control caching in the class: set the cache
with an instance of a DataCache
implementation or with a callable, start and
stop using the cache and tell whether the cache is in use or not.
class MyCacheAware implements CacheAware { public function someMethod() { // ... if ($this->isCacheInUse()) { // do something with the cache $this->getDataCache()->set(...); } } } $myInstance = new MyCacheWare(...); $myInstance->setCache($someDataCacheInstanceOrSomeCallable); $myInstance->useCache(); $myInstance->someMethod(); // cache will be used $myInstance->doNotUseCache(); $myInstance->someMethod(); // cache will not be used
The trait SimpleCacheAwareTrait
provided in this package implements this interface.