MemoryDriver::get()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 14
c 0
b 0
f 0
ccs 8
cts 8
cp 1
rs 9.4285
cc 2
eloc 8
nc 1
nop 1
crap 2
1
<?php
2
3
namespace AsyncPHP\Icicle\Cache\Driver;
4
5
use AsyncPHP\Icicle\Cache\Driver;
6
use Icicle\Concurrent\Forking\Fork;
7
use Icicle\Coroutine;
8
use Icicle\Loop;
9
use Icicle\Promise;
10
use Icicle\Promise\Deferred;
11
use Icicle\Promise\PromiseInterface;
12
13
class MemoryDriver implements Driver
14
{
15
    /**
16
     * @var array
17
     */
18
    private $cache = [];
19
20
    /**
21
     * @var array
22
     */
23
    private $waiting = [];
24
25
    /**
26
     * @var array
27
     */
28
    private $busy = [];
29
30
    /**
31
     * @inheritdoc
32
     *
33
     * @param string $key
34
     *
35
     * @return PromiseInterface
36
     *
37
     * @resolve mixed
38
     */
39 3
    public function get($key)
40
    {
41 3
        $deferred = new Deferred();
42
43
        Loop\queue(function () use ($deferred, $key) {
44 3
            if ($this->busy($deferred, $key)) {
45 1
                $this->wait($deferred, $key);
46 1
            } else {
47 3
                $deferred->resolve($this->value($key));
48
            }
49 3
        });
50
51 3
        return $deferred->getPromise();
52
    }
53
54
    /**
55
     * @param Deferred $deferred
56
     * @param string $key
57
     *
58
     * @return bool
59
     */
60 5
    private function busy(Deferred $deferred, $key)
61
    {
62 5
        return isset($this->busy[$key]) and spl_object_hash($this->busy[$key]) !== spl_object_hash($deferred);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
63
    }
64
65
    /**
66
     * @param Deferred $deferred
67
     * @param string $key
68
     */
69 1
    private function wait(Deferred $deferred, $key)
70
    {
71 1
        if (!isset($this->waiting[$key])) {
72 1
            $this->waiting[$key] = [];
73 1
        }
74
75 1
        $this->waiting[$key][] = $deferred;
76 1
    }
77
78
    /**
79
     * @param string $key
80
     *
81
     * @return mixed
82
     */
83 3
    private function value($key)
84
    {
85 3
        if (isset($this->cache[$key])) {
86 1
            return $this->cache[$key];
87
        }
88
89 2
        return null;
90
    }
91
92
    /**
93
     * @inheritdoc
94
     *
95
     * @param string $key
96
     * @param mixed $value
97
     *
98
     * @return PromiseInterface
99
     *
100
     * @resolve mixed
101
     */
102 4
    public function set($key, $value)
103
    {
104 4
        $deferred = new Deferred();
105
106
        Loop\queue(function () use ($deferred, $key, $value) {
107 4
            if ($this->busy($deferred, $key)) {
108 1
                $this->wait($deferred, $key);
109 1
            } else {
110
                Coroutine\create(function () use ($deferred, $key, $value) {
111 4
                    $this->busy[$key] = $deferred;
112
113 4
                    if (is_callable($value)) {
114 2
                        $fork = Fork::spawn($value);
115 2
                        $value = (yield $fork->join());
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $value, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
116 2
                    }
117
118 4
                    $this->cache[$key] = $value;
119 4
                    unset($this->busy[$key]);
120
121 4
                    if (isset($this->waiting[$key])) {
122 1
                        while (count($this->waiting[$key])) {
123
                            /** @var Deferred $next */
124 1
                            $next = array_shift($this->waiting[$key]);
125
126 1
                            $next->resolve($value);
127 1
                        }
128 1
                    }
129
130 4
                    $deferred->resolve($value);
131 4
                });
132
            }
133 4
        });
134
135 4
        return $deferred->getPromise();
136
    }
137
138
    /**
139
     * @inheritdoc
140
     *
141
     * @param string $key
142
     *
143
     * @return PromiseInterface
144
     *
145
     * @resolve void
146
     */
147 1
    public function forget($key)
148
    {
149 1
        $deferred = new Deferred();
150
151 1
        Loop\queue(function () use ($deferred, $key) {
152 1
            unset($this->cache[$key]);
153 1
            $deferred->resolve();
154 1
        });
155
156 1
        return $deferred->getPromise();
157
    }
158
}
159