Passed
Branch master (0b4094)
by Alexander
01:32
created

ArrayCache::setMultiple()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 2
rs 10
1
<?php
2
3
namespace Yiisoft\Cache;
4
5
use DateInterval;
6
use DateTime;
7
use Psr\SimpleCache\CacheInterface;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Yiisoft\Cache\CacheInterface. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
9
/**
10
 * ArrayCache provides caching for the current request only by storing the values in an array.
11
 *
12
 * See {@see \Psr\SimpleCache\CacheInterface} for common cache operations that ArrayCache supports.
13
 */
14
final class ArrayCache implements CacheInterface
15
{
16
    private const EXPIRATION_INFINITY = 0;
17
    private const EXPIRATION_EXPIRED = -1;
18
    private const TTL_EXPIRED = -1;
19
20
    private $cache = [];
21
22 136
    public function get($key, $default = null)
23
    {
24 136
        if (isset($this->cache[$key]) && !$this->isExpired($key)) {
25 114
            $value = $this->cache[$key][0];
26 114
            if (is_object($value)) {
27 20
                $value = clone $value;
28
            }
29
30 114
            return $value;
31
        }
32
33 57
        return $default;
34
    }
35
36 156
    public function set($key, $value, $ttl = null): bool
37
    {
38 156
        $expiration = $this->ttlToExpiration($ttl);
39 156
        if ($expiration < 0) {
40 2
            return $this->delete($key);
41
        }
42 156
        if (is_object($value)) {
43 46
            $value = clone $value;
44
        }
45 156
        $this->cache[$key] = [$value, $expiration];
46 156
        return true;
47
    }
48
49 24
    public function delete($key): bool
50
    {
51 24
        unset($this->cache[$key]);
52 24
        return true;
53
    }
54
55 158
    public function clear(): bool
56
    {
57 158
        $this->cache = [];
58 158
        return true;
59
    }
60
61 21
    public function getMultiple($keys, $default = null): iterable
62
    {
63 21
        $results = [];
64 21
        foreach ($keys as $key) {
65 21
            $value = $this->get($key, $default);
66 21
            $results[$key] = $value;
67
        }
68 21
        return $results;
69
    }
70
71 27
    public function setMultiple($values, $ttl = null): bool
72
    {
73 27
        foreach ($values as $key => $value) {
74 27
            $this->set($key, $value, $ttl);
75
        }
76 27
        return true;
77
    }
78
79 2
    public function deleteMultiple($keys): bool
80
    {
81 2
        foreach ($keys as $key) {
82 2
            $this->delete($key);
83
        }
84 2
        return true;
85
    }
86
87 32
    public function has($key): bool
88
    {
89 32
        return isset($this->cache[$key]) && !$this->isExpired($key);
90
    }
91
92
    /**
93
     * Checks whether item is expired or not
94
     * @param string $key
95
     * @return bool
96
     */
97 116
    private function isExpired(string $key): bool
98
    {
99 116
        return $this->cache[$key][1] !== 0 && $this->cache[$key][1] <= time();
100
    }
101
102
    /**
103
     * Converts TTL to expiration
104
     * @param int|DateInterval|null $ttl
105
     * @return int
106
     */
107 162
    private function ttlToExpiration($ttl): int
108
    {
109 162
        $ttl = $this->normalizeTtl($ttl);
110
111 162
        if ($ttl === null) {
112 154
            $expiration = static::EXPIRATION_INFINITY;
113 12
        } elseif ($ttl <= 0) {
114 4
            $expiration = static::EXPIRATION_EXPIRED;
115
        } else {
116 8
            $expiration = $ttl + time();
117
        }
118
119 162
        return $expiration;
120
    }
121
122
    /**
123
     * @noinspection PhpDocMissingThrowsInspection DateTime won't throw exception because constant string is passed as time
124
     *
125
     * Normalizes cache TTL handling `null` value and {@see DateInterval} objects.
126
     * @param int|DateInterval|null $ttl raw TTL.
127
     * @return int|null TTL value as UNIX timestamp or null meaning infinity
128
     */
129 174
    private function normalizeTtl($ttl): ?int
130
    {
131 174
        if ($ttl instanceof DateInterval) {
132 5
            return (new DateTime('@0'))->add($ttl)->getTimestamp();
133
        }
134
135 170
        return $ttl;
136
    }
137
}
138