/**
* Shared between increment/decrement: both have mostly the same logic
* (decrement just increments a negative value), but need their validation
* & use of non-ttl native methods split up.
*
* @param string $key
* @param int $offset
* @param int $initial
* @param int $expire
*
* @return int|bool
*/
protected function doIncrement($key, $offset, $initial, $expire)
{
$ttl = $this->ttl($expire);
$this->client->watch($key);
$value = $this->client->get($key);
if ($value === false) {
/*
* Negative ttl behavior isn't properly documented & doesn't always
* appear to treat the value as non-existing. Let's play safe and not
* even create the value (also saving a request)
*/
if ($ttl < 0) {
return true;
}
// value is not yet set, store initial value!
$this->client->multi();
$this->client->set($key, $initial, $ttl);
/** @var bool[] $return */
$return = (array) $this->client->exec();
return !in_array(false, $return) ? $initial : false;
}
// can't increment if a non-numeric value is set
if (!is_numeric($value) || $value < 0) {
/*
* HHVM Redis only got unwatch recently.
* @see https://github.com/asgrim/hhvm/commit/bf5a259cece5df8a7617133c85043608d1ad5316
*/
if (method_exists($this->client, 'unwatch')) {
$this->client->unwatch();
} else {
// this should also kill the watch...
$this->client->multi()->discard();
}
return false;
}
$value += $offset;
// value can never be lower than 0
$value = max(0, $value);
$this->client->multi();
/*
* Negative ttl behavior isn't properly documented & doesn't always
* appear to treat the value as non-existing. Let's play safe and just
* delete it right away!
*/
if ($ttl < 0) {
$this->client->del($key);
} else {
$this->client->set($key, $value, $ttl);
}
/** @var bool[] $return */
$return = (array) $this->client->exec();
return !in_array(false, $return) ? $value : false;
}