This documentation has the following sections:
- Calling the Class
- The Class Constructor
- PSR-16 Parameters
- PSR-16 Methods
- SimpleCacheRedis Specific Methods
- Exceptions
Please note the PSR-16 related notes here are only partial. To read the full interface specification, please see the PHP-FIG website:
https://www.php-fig.org/psr/psr-16/
An Appendix follows the section on Exceptions.
NOTE: I am sometimes accused of being too verbose when I write documentation. For less verbose documentation, you can read the code itself.
To interface with Redis, you need to create a Redis object. This class does not create one for you as there are far too many different configuration options you may need to specify.
For simple cases where Redis is running on the same server, this usually works:
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
If you need more complexity than that, see the
PECL Connection documentation.
Once you have that object, you can create an instance of the SimpleCacheRedis
class.
The easiest way to create an object of the SimpleCacheRedis class:
use \AWonderPHP\SimpleCacheRedis\SimpleCacheRedis as SimpleCache;
$CacheObj = new SimpleCache($redis);
Note that the $redis argument is passed as the first argument to the
constructor, it is required.
NOTE: To use the encrytion enabled version of this class, use the class
SimpleCacheRedisSodium instead of SimpleCacheRedis. Also, that variant of
this class has a second required argument when creating an instance of the
class, see the SODIUM.md file.
The class constructor takes four parameters:
$redisObject-- Required, the connector object to the Redis server.$webappPrefix-- defaults toNULL$salt-- defaults toNULL$strictType-- defaults toFALSE
NOTE: To use the encryption enabled version of the class, see the
SODIUM.md file for the constructor instructions.
Key collisions are possible when two different web applications or the same web application on two different virtual hosts running on the same web server use the same key for different data.
Key collisions are bad. Not only can they potentially screw up how your application works, but they can potentially leak information.
To solve this problem, this class modifies the key supplied to it to provide a namespaced internal key to use with Redis.
The Web Application Prefix is an upper case alpha-numeric [A-Z0-9] string
that is always used at the beginning of the internal key.
By default, this prefix is DEFAULT. You change it by supplying a different
namespace as the second argument when creating an instance of the class:
$CacheObj = new SimpleCache($redis, 'FOOBAR');
The Web Application Prefix must be at least three characters long and can not be longer than 32 characters. It can only contain upper case letters and the numbers 0-9, but the class will convert lower case letters to upper case for you.
The key you supply to the class to store and fetch data with Redis is hashed and a sixteen or twenty character substring (depending on whether you are using the Sodium variant or not) of the hex representation of that hash is then used as part of the internal key.
The benefit of using a hash, I do not have to care what characters are legal to the actual cache engine. If I want to use a username as part of the key and one of my users uses something like “バニーガール” as their username, it's cool. I can feed that to the class and it will hash it to produce a simple ASCII key that will work with any cache engine.
Hashing also obfuscates the real key, which can be of limited benefit in the event there is theft of the Redis data store.
Anyway, if you want to specify a custom salt, you may as the third argument:
$CacheObj = new SimpleCache($redis, 'FOOBAR', 'KmsIs5Q##@6GfpeC@irKIHA');
To specify a custom salt without changing the default namespace, just use
null as the second argument when creating the class object.
When you feed a parameter to a function or class method, that parameter has two properties: The data itself, and the data type.
When the data type does not match what the function or method expects, there are two options:
- Throw an exception and stop processing.
- Attempt to recast the data type to what is needed.
You can not always do option 2. You can not recast an array as an integer and you can not recast an object as a Boolean, for example.
It also can be dangerous to recast. If a function that normally outputs an integer fails and instead responds with the Boolean type False, that Boolean False if recast as an integer would equate to 0 which may cause problems if the code did not check the data type before using it as an integer.
I prefer Option A, to throw an exception when the data type is not what is expected, but PSR-16 does not specify strict data type checking, so it is an option that is disabled by default. With the default of false, this class recasts data types when I believe it is safe to do so.
To enable strict data type checking, set the fourth option to true:
$CacheObj = new SimpleCache($redis, 'FOOBAR', 'KmsIs5Q##@6GfpeC@irKIHA', true);
If you do not wish to alter the Web Application Prefix or Salt, just use null
for those parameters.
Note that this fourth parameter is the only place where a SimpleCacheRedis method uses type hinting to let PHP know what type the method expects. This is because with type hinting, PHP will automatically recast the type if it can.
Personally I find automatic type casting to be dangerous, so I do not use parameter type hinting very often.
The key associated in a key => value pair MUST be of the type string.
The character A-Z, a-z, 0-9, _, and . MUST be allowed. The
characters {}()/\@: MUST NOT be allowed.
Any other characters are up to the implementer to decide. SimpleCacheRedis has no restrictions on characters other than not allowing what PSR-16 specifically forbids.
The key must be at least one character in length and any key length up to 64
characters must be allowed. SimpleCacheRedis allows key lengths up to 255
characters in length.
The key as defined here is referred to as the $key parameter when used in
the context of a method or function elsewhere in this documentation.
This parameter is either an integer specifying the number of seconds for which the cached value is to be considered valid or a valid DateInterval object that specifies how long the cached value is to ve considered valid
This parameter is referred to as the $ttl when used in the context of a
method or function elsewhere in this documentation.
If an integer is specified as the $ttl parameter that is greater than the
current number of seconds since Unix Epoch, this class will assume you are
specifying an intended expiration rather than a TTL that is longer than the
hardware your server is running on will live.
If the TTL evaluates to a time in the past, this class will throw an exception as that certainly is not what you intend and indicates a bug in your code that you need to know about.
For the set and setMultiple methods, the implementation here also accepts
a type string if the string can be interpreted by the core PHP strtotime()
function.
This section describes the methods defined by the PSR-16 interface specification. These methods will be available in any cache class that implements PSR-16.
This method will attempt to fetch the value associated with key and will
return it. If there is not a key => value pair associated with the $key
then the method will return whatever is specified by $default and if a
$default value is not specified when calling this method, it will return
null.
This method will attempt to set the key => value with the specified $ttl.
It returns a boolean type TRUE on success and FALSE on failure.
If the $ttl parameter is not specified, the class default TTL will be used.
If you specify a TTL of 0 in the set function, thy key => value pair will
be cached as long as possible.
If you specify a TTL of -1 in the set function and you have previously set
the default TTL to at least 6000 seconds (100 minutes), then a random number of
seconds between 0 and 15% of the default TTL will randomly be added or
substracted to the default TTL and used. This is to allow staggering the cache
expiration when you cache a lot of items at once, such as with cache warming.
This method will attempt to delete the key => value pair associated with the
specified $key. It returns a Boolean type TRUE on success and FALSE on
failure.
In PSR-16 this method will remove all key => value pairs from the cache.
Since SimpleCacheRedis implements a form of namespacing with the Web Application Prefix, I deviate from PSR-16 in my implementation of this method. I only clear the records associated with the Web Application Prefix associated with the object the method is being called from.
If you do not use more than one Web Application Prefix, then it effectively is the same as clearing them all.
If you do use more than one Web Application Prefix, then clearing them all is probably not what you actually want.
This method returns a Boolean type TRUE on success and FALSE on failure.
In this method, the parameter $keys MUST be a
Traversable pseudo-type
(a type that can be traversed with the
foreach language
construct).
Usually that means an array, but some objects are also traversible.
The method allows you to request many key => value pairs at once. It returns
a traversible type with key => value using $default as the value associated
with keys that are not in the cache. If you do not specify the $default
parameter, it defaults to NULL.
In the SimpleCacheRedis implementation, it returns a key => value array.
In this method, the parameter $values MUST be a Traversible pseudo-type
containing key => value pairs. The key MUST be a string that meets the
earlier conditions.
The $ttl parameter if specified indicates the TTL that should be used for all
the key => value pairs, this method does not support specifying a different
TTL to use depending on the individual pair.
This method returns a Boolean type TRUE on success and FALSE on failure.
If you specify a TTL of 0 in the setMultiple function, thy key => value
pair will be cached as long as possible.
If you specify a TTL of -1 in the setMultiple function and you have
previously set the default TTL to at least 6000 seconds (100 minutes), then a
random number of seconds between 0 and 15% of the default TTL will randomly be
added or substracted to the default TTL and used. This is to allow staggering
the cache expiration when you cache a lot of items at once, such as with cache
warming.
In this method, the parameter $keys MUST be a Traversible pseudo-type
containing keys you want deleted from the cache.
This method returns a Boolean type TRUE on success and FALSE on failure.
This method checks to see whether or not the specified $key has a value
stored in the cache.
If it does, it return a Boolean TRUE, otherwise it returns FALSE.
In addition to providing the PSR-16 specified methods, this class offers a few others.
This allows you to specify the default number of seconds to use for the TTL
when it is not specified in the set() or setMultiple() methods.
By default, the value is 0 which tells Redis to keep the key => value
pair in cache until you specifically replace it or specifically delete it.
Personally I think that rarely is a good idea. Web applications SHOULD either delete the cached entry or update the cached entry when the data is no longer valid, but because programmers are human, the code to do that is not always written or bug free.
Setting the default to something like two weeks (1209600) helps reduce the
impact of stale cache.
Regardless of what you set the default to, if $ttl is specified when the
set() or setMultiple() method is called it will ALWAYS override the
default.
This calls flushDB() which will clear all cache entries, regardless of what
the Web Application Prefix is set to. If you use more than one Prefix, this
probably is not what you want to do.
This is the equivalent of the PSR-16 clear() method.
The key the web application uses to interface with SimpleCacheRedis is different than the key SimpleCacheRedis uses to interface with Redis.
This method returns the internal key SimpleCacheRedis uses to talk to Redis.
It is needed for unit testing.
There are three conditions that can cause SimpleCacheRedis to intentionally throw an exception:
- The data type used in a parameter is incorrect
- The data used in a parameter is not valid for use
- There is an issue connecting with the Redis server or if you are using the Sodium variant, there is an issue that will prevent encryption from working.
Exceptions of this type are thrown under one of the following circumstances:
-
You have set
$strictTypetoTRUEbut supplied a parameter that does not match the expected data type. -
You do not have
$strictTypeset toTRUEbut it would not be safe to try and recast the data type to what is required. -
It is not possible to recast the data type to what is required.
This usually indicates a serious problem with your code that needs to be resolved, your code should not be trying to pass parameters to methods and functions that are of the wrong type, and when it does, it often indicates an uncaught error happened somewhere (or it is sloppy code).
Under those circumstances, this class will throw a:
\AWonderPHP\SimpleCache\StrictTypeException
extends \TypeError
implements \Psr\SimpleCache\InvalidArgumentException
Exception.
You can catch these based on \TypeError or the PSR implementation.
Exceptions of this type are thrown when the data type is valid but the data
itself is not valid. For example, your $key may be a valid string but might
contain one of the characters PSR-16 considers to be reserved.
In those circumstances, this class will throw a:
\AWonderPHP\SimpleCache\InvalidArgumentException
extends \InvalidArgumentException
implements \Psr\SimpleCache\InvalidArgumentException
Exception.
You can catch these based on \InvalidArgumentException or the PSR
implementation.
Exceptions of this type only happen when either the class is not able to connect to the Redis server, you are using the Sodium variant and do not have the libsodium functions available, you specified a JSON configuration file that does not exist or is invalid, your encryption key is not valid, or something is broken resulting in the encryption nonce not being properly incremented.
In those circumstances, this class will throw a:
\AWonderPHP\SimpleCache\InvalidSetupException
extends \ErrorException
implements \Psr\SimpleCache\CacheException
Exception.
You can catch these based on \ErrorException or the PSR implementation.
Catching Exceptions allows your code to gracefully handle the error. The way to
catch an exception is with a try{}catch(){} block:
try{
$CacheObj->get($key);
} catch(\TypeError $e) {
// code to handle based on $e
} catch(\InvalidArgumentException $e) {
// code to handle based on $e
} catch(\Error $e) {
// code to handle based on $e
}
That code takes advantage of which Exception classes in core PHP are extended
by SimpleCacheRedis with the third catch block catching Exceptions that are
not extensions of \TypeError or \InvalidArgument.
The above does not distinguish between Exceptions intentionally thrown by the class and Exceptions thrown by methods and functions the class calls.
If you wish to do that, then catch the Exceptions based on the PSR-16 interfaces for exceptions before the more generic Exception classes.
It is my opinion that when a web application implements a third party library such as this one that is an implementation of a standardized interface such as PSR-16, the web application should create a class that extends the third party library.
This way if, for example, I do become homeless and am not able to maintain this class as bugs are found or as PHP continues to evolve and deprecate ways of doing things this class uses, you can either modify your extended class to use a different implementation of PSR-16 or you can modify your extended class to replace methods in this class that need to be patched.
Only your extended class needs to be modified, the rest of your code then calls your extended class and continues to work.
namespace YourCompany/YourProducted/ThirdPartyExtended
class CustomCacheWrapper extends \AWonderPHP\SimpleCacheRedis\SimpleCacheRedis
{
public function __construct($redis)
{
$MyAppNamespace = 'COOLBANANAS';
$MySalt = 'pFfbk5fAWppb4zxF6lRprKNcLsgAqV2irUe';
parent::__construct($redis, $MyAppNamespace, $MySalt, true);
}
}
In your web application code where you need an instance of a PSR-16 compliant cache handler:
use \YourCompany\YourProducted\ThirdPartyExtended\CustomCacheWrapper as SimpleCache;
$CacheObj = new SimpleCache;
If you then ever need to use a different class for your PSR-16 implementation,
all you need to do is modify the extended class to extend the different
implementation and modify the __construct method to suit the new class you
are using.
You can also of course add custom methods of your own.
Unit tests are currently being done with PHPUnit 7.
The current results as run on my system are in the file UnitTestResults.txt
EOF