Completed
Push — master ( 93e29b...ebea66 )
by Randy
01:58
created

EnsuranceTrait::is()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Dgame\Ensurance;
4
5
use Dgame\Ensurance\Exception\EnsuranceException;
6
use Dgame\Type\Type;
7
use Throwable;
8
9
/**
10
 * Trait EnsuranceTrait
11
 * @package Dgame\Ensurance
12
 */
13
trait EnsuranceTrait
14
{
15
    /**
16
     * @var mixed
17
     */
18
    private $value;
19
    /**
20
     * @var bool
21
     */
22
    private $ensured = true;
23
    /**
24
     * @var Throwable
25
     */
26
    private $throwable;
27
28
    /**
29
     *
30
     */
31
    public function __destruct()
32
    {
33
        if ($this->hasThrowable()) {
34
            throw $this->throwable;
35
        }
36
    }
37
38
    /**
39
     * @param callable $callback
40
     *
41
     * @return self
42
     */
43
    final public function is(callable $callback): self
44
    {
45
        try {
46
            $result = (bool) $callback($this->value);
47
        } catch (Throwable $t) {
48
            $result = false;
49
        }
50
51
        return $this->ensure($result);
52
    }
53
54
    /**
55
     * @param string $type
56
     *
57
     * @return EnsuranceTrait
0 ignored issues
show
Comprehensibility Bug introduced by
The return type EnsuranceTrait is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?

In PHP traits cannot be used for type-hinting as they do not define a well-defined structure. This is because any class that uses a trait can rename that trait’s methods.

If you would like to return an object that has a guaranteed set of methods, you could create a companion interface that lists these methods explicitly.

Loading history...
58
     * @throws \Exception
59
     */
60
    final public function isTypeOf(string $type): self
61
    {
62
        $type = Type::import($type);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $type. This often makes code more readable.
Loading history...
63
64
        return $this->ensure($type->accept($this->value));
65
    }
66
67
    /**
68
     * @param $value
69
     *
70
     * @return mixed
71
     */
72
    final public function then($value)
73
    {
74
        return $this->disregardThrowable()->isEnsured() ? $value : $this->value;
75
    }
76
77
    /**
78
     * @param $value
79
     *
80
     * @return mixed
81
     */
82
    final public function else($value)
0 ignored issues
show
Bug introduced by
Possible parse error: non-abstract method defined as abstract
Loading history...
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
83
    {
84
        return $this->disregardThrowable()->isEnsured() ? $this->value : $value;
85
    }
86
87
    /**
88
     * @param $value
89
     *
90
     * @return Either
91
     */
92
    final public function either($value): Either
93
    {
94
        return new Either($value, $this->disregardThrowable()->isEnsured());
95
    }
96
97
    /**
98
     * @param mixed $default
99
     *
100
     * @return mixed
101
     */
102
    final public function get($default = null)
103
    {
104
        return $this->value ?? $default;
105
    }
106
107
    /**
108
     * @param bool $condition
109
     *
110
     * @return self
111
     */
112
    final protected function ensure(bool $condition): self
113
    {
114
        $this->ensured = $condition;
115
116
        return $this;
117
    }
118
119
    /**
120
     * @return bool
121
     */
122
    final public function isEnsured(): bool
123
    {
124
        return $this->ensured;
125
    }
126
127
    /**
128
     * @return self
129
     */
130
    final public function disregardThrowable(): self
131
    {
132
        $this->throwable = null;
133
134
        return $this;
135
    }
136
137
    /**
138
     * @return Throwable
139
     */
140
    final public function releaseThrowable(): Throwable
141
    {
142
        try {
143
            return $this->throwable;
144
        } finally {
145
            $this->disregardThrowable();
0 ignored issues
show
Unused Code introduced by
$this->disregardThrowable(); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
146
        }
147
    }
148
149
    /**
150
     * @param EnsuranceInterface $ensurance
151
     *
152
     * @return self
153
     */
154
    final public function transferEnsurance(EnsuranceInterface $ensurance): self
155
    {
156
        $this->value = $ensurance->get();
157
        $this->ensure($ensurance->isEnsured());
158
        if ($ensurance->hasThrowable()) {
159
            $this->setThrowable($ensurance->releaseThrowable());
160
        }
161
162
        return $this;
163
    }
164
165
    /**
166
     * @param string $message
167
     * @param mixed  ...$args
168
     *
169
     * @return self
170
     */
0 ignored issues
show
Documentation introduced by
Consider making the type for parameter $args a bit more specific; maybe use array.
Loading history...
171
    final public function orThrow(string $message, ...$args): self
172
    {
173
        if (!$this->isEnsured()) {
174
            $this->setThrowable(new EnsuranceException(format($message, ...$args), $this->throwable));
175
        }
176
177
        return $this;
178
    }
179
180
    /**
181
     * @return bool
182
     */
183
    final public function hasThrowable(): bool
184
    {
185
        return $this->throwable !== null;
186
    }
187
188
    /**
189
     * @param Throwable $throwable
190
     *
191
     * @return self
192
     */
193
    final public function setThrowable(Throwable $throwable): self
194
    {
195
        if (!$this->isEnsured()) {
196
            $this->throwable = $throwable;
197
        }
198
199
        return $this;
200
    }
201
202
    /**
203
     * @return Throwable
204
     */
205
    final public function getThrowable(): Throwable
206
    {
207
        return $this->throwable;
208
    }
209
}
210