Test Failed
Pull Request — master (#43)
by
unknown
02:20
created

ApcuStorage::saveCompareAndSwap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
eloc 3
c 2
b 0
f 2
dl 0
loc 6
rs 10
cc 1
nc 1
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\RateLimiter\Storage;
6
7
use InvalidArgumentException;
8
use Yiisoft\Yii\RateLimiter\Exception\CannotUseException;
9
10
/**
11
 * To use this storage, the [APCu PHP extension](http://www.php.net/apcu) must be loaded,
12
 * And you should add "apc.enabled = 1" to your php.ini.
13
 * In order to enable APCu for CLI you should add "apc.enable_cli = 1" to your php.ini.
14
 */
15
final class ApcuStorage implements StorageInterface
16
{
17
    private const DEFAULT_FIX_PRECISION_RATE = 1000;
18
19
    /**
20
     * @param int $fixPrecisionRate 
21
     * Apcu_cas of ACPu does not support float,  and yet supports int.
22
     * APCu's stored value multiply by $fixPrecisionRate converts to int,
23
     * AND the getter's value divide by $fixPrecisionRate converts to float.
24
     * So use it to improve precision.
25
     */
26
    public function __construct(
27
        private int $fixPrecisionRate = self::DEFAULT_FIX_PRECISION_RATE
28
    ) {
29
        if (!extension_loaded('apcu') || !ini_get('apc.enabled')) {
30
            throw new CannotUseException('APCu extension is not loaded or not enabled.');
31
        }
32
    }
33
34
    public function saveIfNotExists(string $key, int|float $value, int $ttl): bool
35
    {
36
        $value = (int) ($value * $this->fixPrecisionRate);
37
38
        return apcu_add($key, $value, $ttl);
0 ignored issues
show
Bug Best Practice introduced by
The expression return apcu_add($key, $value, $ttl) could return the type array which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
39
    }
40
41
    public function saveCompareAndSwap(string $key, int|float $oldValue, int|float $newValue, int $ttl): bool
42
    {
43
        $oldValue = (int) ($oldValue * $this->fixPrecisionRate);
44
        $newValue = (int) ($newValue * $this->fixPrecisionRate);
45
46
        return apcu_cas($key, $oldValue, $newValue);
47
    }
48
49
    public function get(string $key): ?float
50
    {
51
        $value = apcu_fetch($key);
52
        if (!is_int($value) && !is_float($value) && $value !== false) {
53
            throw new InvalidArgumentException('The value is not supported by ApcuStorage, it must be int, float.');
54
        }
55
56
        if ($value !== false) {
57
            $value = (float)$value / $this->fixPrecisionRate;
58
        } else {
59
            $value = null;
60
        }
61
        return $value;
62
    }
63
}
64