Completed
Push — master ( 7ccc1c...c2f572 )
by Randy
01:22
created

EnsuranceTrait::hasThrowable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
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 Dgame\Type\TypeFactory;
8
use Throwable;
9
10
/**
11
 * Trait EnsuranceTrait
12
 * @package Dgame\Ensurance
13
 */
14
trait EnsuranceTrait
15
{
16
    /**
17
     * @var mixed
18
     */
19
    private $value;
20
    /**
21
     * @var bool
22
     */
23
    private $ensured = true;
24
    /**
25
     * @var Throwable
26
     */
27
    private $throwable;
28
29
    /**
30
     *
31
     */
32
    public function __destruct()
33
    {
34
        if ($this->hasThrowable()) {
35
            throw $this->throwable;
36
        }
37
    }
38
39
    /**
40
     * @param callable $callback
41
     *
42
     * @return self
43
     */
44
    final public function is(callable $callback): self
45
    {
46
        try {
47
            $result = (bool) $callback($this->value);
48
        } catch (Throwable $t) {
49
            $result = false;
50
        }
51
52
        return $this->ensure($result);
53
    }
54
55
    /**
56
     * @param string $type
57
     *
58
     * @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...
59
     * @throws \Exception
60
     */
61
    final public function isTypeOf(string $type): self
62
    {
63
        $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...
64
65
        return $this->ensure(TypeFactory::expression($this->value)->isSame($type));
66
    }
67
68
    /**
69
     * @param $value
70
     *
71
     * @return mixed
72
     */
73
    final public function then($value)
74
    {
75
        return $this->disregardThrowable()->isEnsured() ? $value : $this->value;
76
    }
77
78
    /**
79
     * @param $value
80
     *
81
     * @return mixed
82
     */
83
    final public function else($value)
84
    {
85
        return $this->disregardThrowable()->isEnsured() ? $this->value : $value;
86
    }
87
88
    /**
89
     * @param $value
90
     *
91
     * @return Either
92
     */
93
    final public function either($value): Either
94
    {
95
        return new Either($value, $this->disregardThrowable()->isEnsured());
96
    }
97
98
    /**
99
     * @param mixed $default
100
     *
101
     * @return mixed
102
     */
103
    final public function get($default = null)
104
    {
105
        return $this->value ?? $default;
106
    }
107
108
    /**
109
     * @param bool $condition
110
     *
111
     * @return self
112
     */
113
    final protected function ensure(bool $condition): self
114
    {
115
        $this->ensured = $condition;
116
117
        return $this;
118
    }
119
120
    /**
121
     * @return bool
122
     */
123
    final public function isEnsured(): bool
124
    {
125
        return $this->ensured;
126
    }
127
128
    /**
129
     * @return self
130
     */
131
    final public function disregardThrowable(): self
132
    {
133
        $this->throwable = null;
134
135
        return $this;
136
    }
137
138
    /**
139
     * @return Throwable
140
     */
141
    final public function releaseThrowable(): Throwable
142
    {
143
        try {
144
            return $this->throwable;
145
        } finally {
146
            $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...
147
        }
148
    }
149
150
    /**
151
     * @param EnsuranceInterface $ensurance
152
     *
153
     * @return self
154
     */
155
    final public function transferEnsurance(EnsuranceInterface $ensurance): self
156
    {
157
        $this->value = $ensurance->get();
158
        $this->ensure($ensurance->isEnsured());
159
        if ($ensurance->hasThrowable()) {
160
            $this->orThrowWith($ensurance->releaseThrowable());
161
        }
162
163
        return $this;
164
    }
165
166
    /**
167
     * @param string $message
168
     * @param mixed  ...$args
169
     *
170
     * @return self
171
     */
0 ignored issues
show
Documentation introduced by
Consider making the type for parameter $args a bit more specific; maybe use array.
Loading history...
172
    final public function orThrow(string $message, ...$args): self
173
    {
174
        if (!$this->isEnsured()) {
175
            $this->orThrowWith(new EnsuranceException(format($message, ...$args), $this->throwable));
176
        }
177
178
        return $this;
179
    }
180
181
    /**
182
     * @return bool
183
     */
184
    final public function hasThrowable(): bool
185
    {
186
        return $this->throwable !== null;
187
    }
188
189
    /**
190
     * @param Throwable $throwable
191
     *
192
     * @deprecated Use "orThrowWith" instead
193
     *
194
     * @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...
195
     */
196
    final public function setThrowable(Throwable $throwable): self
197
    {
198
        return $this->orThrowWith($throwable);
199
    }
200
201
    /**
202
     * @param Throwable $throwable
203
     *
204
     * @return self
205
     */
206
    final public function orThrowWith(Throwable $throwable): self
207
    {
208
        if (!$this->isEnsured()) {
209
            $this->throwable = $throwable;
210
        }
211
212
        return $this;
213
    }
214
215
    /**
216
     * @return Throwable
217
     */
218
    final public function getThrowable(): Throwable
219
    {
220
        return $this->throwable;
221
    }
222
}
223