InMemoryAdapter::storageDataStructure()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 8
rs 9.4286
cc 3
eloc 4
nc 3
nop 1
1
<?php
2
3
namespace NilPortugues\Cache\Adapter;
4
5
use DateTime;
6
use NilPortugues\Cache\CacheAdapter;
7
8
/**
9
 * Class InMemoryAdapter
10
 * @package NilPortugues\Cache\Adapter
11
 */
12
class InMemoryAdapter extends Adapter implements CacheAdapter
13
{
14
    /**
15
     * @var array
16
     */
17
    private static $registry = [];
18
19
    /**
20
     * @var self Reference to singleton instance
21
     */
22
    private static $instance;
23
24
    /**
25
     * is not allowed to call from outside: private!
26
     *
27
     */
28
    protected function __construct()
29
    {
30
    }
31
32
    /**
33
     * gets the instance via lazy initialization (created on first usage)
34
     *
35
     * @return self
36
     */
37
    public static function getInstance()
38
    {
39
        if (null === static::$instance) {
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
40
            static::$instance = new static;
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
41
        }
42
        return static::$instance;
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
43
    }
44
45
    /**
46
     * Get a value identified by $key.
47
     *
48
     * @param  string $key
49
     *
50
     * @return bool|mixed
51
     */
52
    public function get($key)
53
    {
54
        $key       = (string)$key;
55
        $value     = null;
56
        $this->hit = false;
57
58
        if (\array_key_exists($key, self::$registry)) {
59
            if (self::$registry[$key]['expires'] >= (new DateTime())) {
60
                $this->hit = true;
61
                return $this->restoreDataStructure($key);
62
            }
63
            unset(self::$registry[$key]);
64
        }
65
66
        return $value;
67
    }
68
69
    /**
70
     * @param string $key
71
     *
72
     * @return mixed
73
     */
74
    protected function restoreDataStructure($key)
75
    {
76
        if ($this->isSerializedArray($key)) {
77
            return \unserialize(self::$registry[$key]['value']);
78
        }
79
80
        return (\is_object(self::$registry[$key]['value'])) ?
81
            clone self::$registry[$key]['value'] :
82
            self::$registry[$key]['value'];
83
    }
84
85
    /**
86
     * @param $key
87
     *
88
     * @return bool
89
     */
90
    private function isSerializedArray($key)
91
    {
92
        return \is_string(self::$registry[$key]['value'])
93
        && 'a:' === \substr(self::$registry[$key]['value'], 0, 2)
94
        && '}' === \substr(self::$registry[$key]['value'], -1)
95
        && (':{i:' === \substr(self::$registry[$key]['value'], 3, 4)
96
            || ':{s:' === \substr(self::$registry[$key]['value'], 3, 4));
97
    }
98
99
    /**
100
     * Set a value identified by $key and with an optional $ttl.
101
     *
102
     * @param string $key
103
     * @param mixed  $value
104
     * @param int    $ttl
105
     *
106
     * @return $this
107
     */
108
    public function set($key, $value, $ttl = 0)
109
    {
110
        $key = (string)$key;
111
        $ttl = $this->fromDefaultTtl($ttl);
112
113
        if ($ttl >= 0) {
114
            $calculatedTtl = $this->getCalculatedTtl($ttl);
115
116
            self::$registry[$key] = [
117
                'value'   => $this->storageDataStructure($value),
118
                'expires' => new DateTime(\date('Y-m-d H:i:s', $calculatedTtl))
119
            ];
120
        }
121
        return $this;
122
    }
123
124
    /**
125
     * @param $ttl
126
     *
127
     * @return int
128
     */
129 View Code Duplication
    private function getCalculatedTtl($ttl)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
    {
131
        $calculatedTtl = \strtotime(\sprintf('now +%s seconds', $ttl));
132
        if (0 == $ttl) {
133
            $calculatedTtl = \strtotime('now +10 years');
134
        }
135
        return $calculatedTtl;
136
    }
137
138
    /**
139
     * @param $value
140
     *
141
     * @return mixed
142
     */
143
    protected function storageDataStructure($value)
144
    {
145
        if (\is_array($value)) {
146
            return \serialize($value);
147
        }
148
149
        return (\is_object($value)) ? clone $value : $value;
150
    }
151
152
    /**
153
     * Delete a value identified by $key.
154
     *
155
     * @param string $key
156
     *
157
     * @return $this
158
     */
159
    public function delete($key)
160
    {
161
        $key = (string)$key;
162
163
        if (\array_key_exists($key, self::$registry)) {
164
            unset(self::$registry[$key]);
165
        }
166
        return $this;
167
    }
168
169
    /**
170
     * Checks the availability of the cache service.
171
     *
172
     * @return bool
173
     */
174
    public function isAvailable()
175
    {
176
        return true;
177
    }
178
179
    /**
180
     * Clears all expired values from cache.
181
     *
182
     * @return mixed
183
     */
184
    public function clear()
185
    {
186
        $currentDate = new DateTime();
187
        foreach (\array_keys(self::$registry) as $key) {
188
            $this->clearExpiredKey($key, $currentDate);
189
        }
190
    }
191
192
    /**
193
     * Clear an item if it expired.
194
     *
195
     * @param          $key
196
     * @param DateTime $dateTime
197
     */
198
    private function clearExpiredKey($key, DateTime $dateTime)
199
    {
200
        if (self::$registry[$key]['expires'] < $dateTime) {
201
            unset(self::$registry[$key]);
202
        }
203
    }
204
205
    /**
206
     * Clears all values from the cache.
207
     *
208
     * @return mixed
209
     */
210
    public function drop()
211
    {
212
        self::$registry = [];
213
    }
214
215
    /**
216
     * prevent the instance from being cloned
217
     *
218
     * @return void
219
     */
220
    protected function __clone()
221
    {
222
    }
223
224
    /**
225
     * prevent from being unserialized
226
     *
227
     * @return void
228
     */
229
    protected function __wakeup()
230
    {
231
    }
232
}
233