Completed
Push — 2.1 ( 28b26f...4d9204 )
by Alexander
10:53
created

Cache::getMultiple()   C

Complexity

Conditions 8
Paths 10

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 8.4218

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 25
ccs 13
cts 16
cp 0.8125
rs 5.3846
cc 8
eloc 17
nc 10
nop 2
crap 8.4218
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\caching;
9
10
use Yii;
11
use yii\base\Component;
12
use yii\di\Instance;
13
use yii\helpers\StringHelper;
14
15
/**
16
 * Cache provides support for the data caching, including cache key composition and dependencies.
17
 * The actual data caching is performed via [[handler]], which should be configured to be [[\Psr\SimpleCache\CacheInterface]]
18
 * instance.
19
 *
20
 * Application configuration example:
21
 *
22
 * ```php
23
 * return [
24
 *     'components' => [
25
 *         'cache' => [
26
 *             'class' => yii\caching\Cache::class,
27
 *             'handler' => [
28
 *                 'class' => yii\caching\FileCache::class,
29
 *                 'cachePath' => '@runtime/cache',
30
 *             ],
31
 *         ],
32
 *         // ...
33
 *     ],
34
 *     // ...
35
 * ];
36
 * ```
37
 *
38
 * A data item can be stored in the cache by calling [[set()]] and be retrieved back
39
 * later (in the same or different request) by [[get()]]. In both operations,
40
 * a key identifying the data item is required. An expiration time and/or a [[Dependency|dependency]]
41
 * can also be specified when calling [[set()]]. If the data item expires or the dependency
42
 * changes at the time of calling [[get()]], the cache will return no data.
43
 *
44
 * A typical usage pattern of cache is like the following:
45
 *
46
 * ```php
47
 * $key = 'demo';
48
 * $data = $cache->get($key);
49
 * if ($data === null) {
50
 *     // ...generate $data here...
51
 *     $cache->set($key, $data, $duration, $dependency);
52
 * }
53
 * ```
54
 *
55
 * Because Cache implements the [[\ArrayAccess]] interface, it can be used like an array. For example,
56
 *
57
 * ```php
58
 * $cache['foo'] = 'some data';
59
 * echo $cache['foo'];
60
 * ```
61
 *
62
 * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview)
63
 * and [PSR-16 specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md).
64
 *
65
 * @author Qiang Xue <[email protected]>
66
 * @since 2.0
67
 */
68
class Cache extends Component implements CacheInterface
69
{
70
    /**
71
     * @var \Psr\SimpleCache\CacheInterface|array|\Closure|string actual cache handler or its DI compatible configuration.
72
     * After the Cache object is created, if you want to change this property, you should only assign it
73
     * with a [[\Psr\SimpleCache\CacheInterface]] instance.
74
     * @since 2.1.0
75
     */
76
    public $handler;
77
78
79
    /**
80
     * {@inheritdoc}
81
     */
82 199
    public function init()
83
    {
84 199
        parent::init();
85 199
        $this->handler = Instance::ensure($this->handler instanceof \Closure ? call_user_func($this->handler) : $this->handler, \Psr\SimpleCache\CacheInterface::class);
86 199
    }
87
88
    /**
89
     * Builds a normalized cache key from a given key.
90
     *
91
     * If the given key is a string containing alphanumeric characters only and no more than 32 characters,
92
     * then the key will be returned back as it is. Otherwise, a normalized key is generated by serializing
93
     * the given key and applying MD5 hashing.
94
     *
95
     * @param mixed $key the key to be normalized
96
     * @return string the generated cache key
97
     */
98 198
    protected function buildKey($key)
99
    {
100 198
        if (is_string($key)) {
101 168
            return ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key);
102
        }
103 30
        return md5(json_encode($key));
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109 105
    public function get($key, $default = null)
110
    {
111 105
        $key = $this->buildKey($key);
112 105
        $value = $this->handler->get($key);
0 ignored issues
show
Bug introduced by
The method get does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
113
114 105
        if ($value === null) {
115 74
            return $default;
116
        }
117
118 86
        if (is_array($value) && isset($value[1]) && $value[1] instanceof Dependency) {
119 7
            if ($value[1]->isChanged($this)) {
120 7
                return $default;
121
            }
122 7
            return $value[0];
123
        }
124
125 79
        return $value;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 8
    public function has($key)
132
    {
133 8
        $key = $this->buildKey($key);
134 8
        return $this->handler->has($key);
0 ignored issues
show
Bug introduced by
The method has does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
135
    }
136
137
    /**
138
     * Retrieves multiple values from cache with the specified keys.
139
     * Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time,
140
     * which may improve the performance. In case a cache does not support this feature natively,
141
     * this method will try to simulate it.
142
     * @param string[] $keys list of string keys identifying the cached values
143
     * @param mixed $default Default value to return for keys that do not exist.
144
     * @return array list of cached values corresponding to the specified keys. The array
145
     * is returned in terms of (key, value) pairs.
146
     * If a value is not cached or expired, the corresponding array value will be false.
147
     * @since 2.0.7
148
     */
149 11
    public function getMultiple($keys, $default = null)
150
    {
151 11
        $keyMap = [];
152 11
        foreach ($keys as $key) {
153 11
            $keyMap[$key] = $this->buildKey($key);
154
        }
155 11
        $values = $this->handler->getMultiple(array_values($keyMap));
0 ignored issues
show
Documentation introduced by
array_values($keyMap) is of type array<integer,?>, but the function expects a object<Psr\SimpleCache\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The method getMultiple does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
156 11
        $results = [];
157 11
        foreach ($keyMap as $key => $newKey) {
158 11
            $results[$key] = $default;
159 11
            if (isset($values[$newKey])) {
160 11
                $value = $values[$newKey];
161 11
                if (is_array($value) && isset($value[1]) && $value[1] instanceof Dependency) {
162
                    if ($value[1]->isChanged($this)) {
163
                        continue;
164
                    } else {
165
                        $value = $value[0];
166
                    }
167
                }
168 11
                $results[$key] = $value;
169
            }
170
        }
171
172 11
        return $results;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $results; (array) is incompatible with the return type declared by the interface Psr\SimpleCache\CacheInterface::getMultiple of type Psr\SimpleCache\iterable.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
173
    }
174
175
    /**
176
     * Stores a value identified by a key into cache.
177
     * If the cache already contains such a key, the existing value and
178
     * expiration time will be replaced with the new ones, respectively.
179
     *
180
     * @param mixed $key a key identifying the value to be cached. This can be a simple string or
181
     * a complex data structure consisting of factors representing the key.
182
     * @param mixed $value the value to be cached
183
     * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
184
     * @param Dependency $dependency dependency of the cached item. If the dependency changes,
185
     * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
186
     * This parameter is ignored if [[serializer]] is false.
187
     * @return bool whether the value is successfully stored into cache
188
     */
189 96
    public function set($key, $value, $ttl = null, $dependency = null)
190
    {
191 96
        if ($dependency !== null) {
192 7
            $dependency->evaluateDependency($this);
193 7
            $value = [$value, $dependency];
194
        }
195 96
        $key = $this->buildKey($key);
196 96
        return $this->handler->set($key, $value, $ttl);
0 ignored issues
show
Bug introduced by
It seems like $ttl defined by parameter $ttl on line 189 can also be of type object<DateInterval>; however, Psr\SimpleCache\CacheInterface::set() does only seem to accept null|integer|object<Psr\SimpleCache\DateInterval>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Bug introduced by
The method set does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
197
    }
198
199
    /**
200
     * Stores multiple items in cache. Each item contains a value identified by a key.
201
     * If the cache already contains such a key, the existing value and
202
     * expiration time will be replaced with the new ones, respectively.
203
     *
204
     * @param array $items the items to be cached, as key-value pairs.
205
     * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
206
     * @param Dependency $dependency dependency of the cached items. If the dependency changes,
207
     * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
208
     * This parameter is ignored if [[serializer]] is false.
209
     * @return array array of failed keys
210
     * @since 2.0.7
211
     */
212 16
    public function setMultiple($items, $ttl = 0, $dependency = null)
213
    {
214 16
        if ($dependency !== null) {
215
            $dependency->evaluateDependency($this);
216
        }
217
218 16
        $data = [];
219 16
        foreach ($items as $key => $value) {
220 16
            if ($dependency !== null) {
221
                $value = [$value, $dependency];
222
            }
223 16
            $key = $this->buildKey($key);
224 16
            $data[$key] = $value;
225
        }
226
227 16
        return $this->handler->setMultiple($data, $ttl);
0 ignored issues
show
Documentation introduced by
$data is of type array, but the function expects a object<Psr\SimpleCache\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The method setMultiple does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
228
    }
229
230
    /**
231
     * {@inheritdoc}
232
     * @since 2.1
233
     */
234
    public function deleteMultiple($keys)
235
    {
236
        $actualKeys = [];
237
        foreach ($keys as $key) {
238
            $actualKeys[] = $this->buildKey($key);
239
        }
240
        return $this->handler->deleteMultiple($actualKeys);
0 ignored issues
show
Documentation introduced by
$actualKeys is of type array, but the function expects a object<Psr\SimpleCache\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The method deleteMultiple does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
241
    }
242
243
    /**
244
     * Stores multiple items in cache. Each item contains a value identified by a key.
245
     * If the cache already contains such a key, the existing value and expiration time will be preserved.
246
     *
247
     * @param array $values the items to be cached, as key-value pairs.
248
     * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
249
     * @param Dependency $dependency dependency of the cached items. If the dependency changes,
250
     * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
251
     * This parameter is ignored if [[serializer]] is false.
252
     * @return array array of failed keys
253
     * @since 2.0.7
254
     */
255 5
    public function addMultiple($values, $ttl = 0, $dependency = null)
256
    {
257 5
        if ($dependency !== null) {
258
            $dependency->evaluateDependency($this);
259
        }
260
261 5
        $data = [];
262 5
        foreach ($values as $key => $value) {
263 5
            if ($dependency !== null) {
264
                $value = [$value, $dependency];
265
            }
266
267 5
            $key = $this->buildKey($key);
268 5
            $data[$key] = $value;
269
        }
270
271 5
        $existingValues = $this->handler->getMultiple(array_keys($data));
0 ignored issues
show
Documentation introduced by
array_keys($data) is of type array<integer,integer|string>, but the function expects a object<Psr\SimpleCache\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The method getMultiple does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
272 5
        foreach ($existingValues as $key => $value) {
273 5
            if ($value !== null) {
274 5
                unset($data[$key]);
275
            }
276
        }
277 5
        return $this->handler->setMultiple($data, $ttl);
0 ignored issues
show
Documentation introduced by
$data is of type array, but the function expects a object<Psr\SimpleCache\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The method setMultiple does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
278
    }
279
280
    /**
281
     * Stores a value identified by a key into cache if the cache does not contain this key.
282
     * Nothing will be done if the cache already contains the key.
283
     * @param mixed $key a key identifying the value to be cached. This can be a simple string or
284
     * a complex data structure consisting of factors representing the key.
285
     * @param mixed $value the value to be cached
286
     * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
287
     * @param Dependency $dependency dependency of the cached item. If the dependency changes,
288
     * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
289
     * This parameter is ignored if [[serializer]] is false.
290
     * @return bool whether the value is successfully stored into cache
291
     */
292 8
    public function add($key, $value, $ttl = null, $dependency = null)
293
    {
294 8
        if ($dependency !== null) {
295
            $dependency->evaluateDependency($this);
296
            $value = [$value, $dependency];
297
        }
298
299 8
        $key = $this->buildKey($key);
300
301 8
        if ($this->handler->has($key)) {
0 ignored issues
show
Bug introduced by
The method has does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
302 5
            return false;
303
        }
304
305 8
        return $this->handler->set($key, $value, $ttl);
0 ignored issues
show
Bug introduced by
It seems like $ttl defined by parameter $ttl on line 292 can also be of type object<DateInterval>; however, Psr\SimpleCache\CacheInterface::set() does only seem to accept null|integer|object<Psr\SimpleCache\DateInterval>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Bug introduced by
The method set does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
306
    }
307
308
    /**
309
     * Deletes a value with the specified key from cache
310
     * @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or
311
     * a complex data structure consisting of factors representing the key.
312
     * @return bool if no error happens during deletion
313
     */
314 93
    public function delete($key)
315
    {
316 93
        $key = $this->buildKey($key);
317
318 93
        return $this->handler->delete($key);
0 ignored issues
show
Bug introduced by
The method delete does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
319
    }
320
321
    /**
322
     * Deletes all values from cache.
323
     * Be careful of performing this operation if the cache is shared among multiple applications.
324
     * @return bool whether the flush operation was successful.
325
     */
326 55
    public function clear()
327
    {
328 55
        return $this->handler->clear();
0 ignored issues
show
Bug introduced by
The method clear does only exist in Psr\SimpleCache\CacheInterface, but not in Closure.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
329
    }
330
331
    /**
332
     * Returns whether there is a cache entry with a specified key.
333
     * This method is required by the interface [[\ArrayAccess]].
334
     * @param string $key a key identifying the cached value
335
     * @return bool
336
     */
337
    public function offsetExists($key)
338
    {
339
        return $this->get($key) !== false;
340
    }
341
342
    /**
343
     * Retrieves the value from cache with a specified key.
344
     * This method is required by the interface [[\ArrayAccess]].
345
     * @param string $key a key identifying the cached value
346
     * @return mixed the value stored in cache, false if the value is not in the cache or expired.
347
     */
348 5
    public function offsetGet($key)
349
    {
350 5
        return $this->get($key);
351
    }
352
353
    /**
354
     * Stores the value identified by a key into cache.
355
     * If the cache already contains such a key, the existing value will be
356
     * replaced with the new ones. To add expiration and dependencies, use the [[set()]] method.
357
     * This method is required by the interface [[\ArrayAccess]].
358
     * @param string $key the key identifying the value to be cached
359
     * @param mixed $value the value to be cached
360
     */
361 50
    public function offsetSet($key, $value)
362
    {
363 50
        $this->set($key, $value);
364 50
    }
365
366
    /**
367
     * Deletes the value with the specified key from cache
368
     * This method is required by the interface [[\ArrayAccess]].
369
     * @param string $key the key of the value to be deleted
370
     */
371
    public function offsetUnset($key)
372
    {
373
        $this->delete($key);
374
    }
375
376
    /**
377
     * Method combines both [[set()]] and [[get()]] methods to retrieve value identified by a $key,
378
     * or to store the result of $callable execution if there is no cache available for the $key.
379
     *
380
     * Usage example:
381
     *
382
     * ```php
383
     * public function getTopProducts($count = 10) {
384
     *     $cache = $this->cache; // Could be Yii::$app->cache
385
     *     return $cache->getOrSet(['top-n-products', 'n' => $count], function ($cache) use ($count) {
386
     *         return Products::find()->mostPopular()->limit(10)->all();
387
     *     }, 1000);
388
     * }
389
     * ```
390
     *
391
     * @param mixed $key a key identifying the value to be cached. This can be a simple string or
392
     * a complex data structure consisting of factors representing the key.
393
     * @param callable|\Closure $callable the callable or closure that will be used to generate a value to be cached.
394
     * In case $callable returns `false`, the value will not be cached.
395
     * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
396
     * @param Dependency $dependency dependency of the cached item. If the dependency changes,
397
     * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
398
     * This parameter is ignored if [[serializer]] is `false`.
399
     * @return mixed result of $callable execution
400
     * @since 2.0.11
401
     */
402 10
    public function getOrSet($key, $callable, $ttl = null, $dependency = null)
403
    {
404 10
        if (($value = $this->get($key)) !== null) {
405 5
            return $value;
406
        }
407
408 10
        $value = call_user_func($callable, $this);
409 10
        if (!$this->set($key, $value, $ttl, $dependency)) {
410
            Yii::warning('Failed to set cache value for key ' . json_encode($key), __METHOD__);
411
        }
412
413 10
        return $value;
414
    }
415
}
416