Completed
Pull Request — master (#57)
by
unknown
01:17
created

Util::handleDefaultCase()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 6
nc 3
nop 3
1
<?php
2
3
namespace TraderInteractive;
4
5
use ErrorException;
6
use Exception;
7
use InvalidArgumentException;
8
use ReflectionClass;
9
use ReflectionException;
10
use Throwable;
11
12
/**
13
 * Static class with various application functions.
14
 */
15
final class Util
16
{
17
    private static $exceptionAliases = ['http' => '\TraderInteractive\HttpException'];
18
19
    /**
20
     * Returns exception info in array.
21
     *
22
     * @param Throwable $t the exception to return info on
23
     *
24
     * @return array like:
25
     * <pre>
26
     * [
27
     *     'type' => 'Exception',
28
     *     'message' => 'a message',
29
     *     'code' => 0,
30
     *     'file' => '/somePath',
31
     *     'line' => 434,
32
     *     'trace' => 'a stack trace',
33
     * ]
34
     * </pre>
35
     */
36
    public static function getExceptionInfo(Throwable $t) : array
37
    {
38
        return [
39
            'type' => get_class($t),
40
            'message' => $t->getMessage(),
41
            'code' => $t->getCode(),
42
            'file' => $t->getFile(),
43
            'line' => $t->getLine(),
44
            'trace' => $t->getTraceAsString(),
45
        ];
46
    }
47
48
    /**
49
     * Ensures that $valueToEnsure is equal to $valueToCheck or it throws
50
     *
51
     * Can be used like: $result = ensure(true, is_string('boo'))
52
     * Or like: $result = ensure(true, is_string('boo'), 'the message')
53
     * Or like: $result = ensure(true, is_string('boo'), 'MyException', ['the message', 2])
54
     * Or like: $result = ensure(true, is_string('boo'), new MyException('the message', 2))
55
     *
56
     * @param mixed      $valueToEnsure            the value to throw on if $valueToCheck equals it
57
     * @param mixed      $valueToCheck             the value to check against $valueToEnsure
58
     * @param mixed      $exception                null, a fully qualified exception class name, string for an Exception
59
     *                                             message, or an Exception.  The fully qualified exception class name
60
     *                                             could also be an alias in getExceptionAliases()
61
     *
62
     * @param array|null $exceptionArgs            arguments to pass to a new instance of $exception. If using this
63
     *                                             parameter make sure these arguments match the constructor for an
64
     *                                             exception of type $exception.
65
     *
66
     * @return mixed returns $valueToCheck
67
     *
68
     * @throws Exception if $valueToEnsure !== $valueToCheck
69
     * @throws InvalidArgumentException if $exception was not null, a string, or an Exception
70
     */
71 View Code Duplication
    public static function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
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...
72
    {
73
        if ($valueToEnsure !== $valueToCheck) {
74
            throw self::buildException(
75
                $exception ?: "'{$valueToEnsure}' did not equal '{$valueToCheck}'",
76
                $exceptionArgs
77
            );
78
        }
79
80
        return $valueToCheck;
81
    }
82
83
    /**
84
     * Ensures that $valueToThrowOn is not equal to $valueToCheck or it throws
85
     *
86
     * Can be used like: $curl = ensureNot(false, curl_init('boo'))
87
     * Or like: $curl = ensureNot(false, curl_init('boo'), 'bad message')
88
     * Or like: $curl = ensureNot(false, curl_init('boo'), 'MyException', ['bad message', 2])
89
     * Or like: $curl = ensureNot(false, curl_init('boo'), new MyException('bad message', 2))
90
     *
91
     * @param mixed                 $valueToThrowOn the value to throw on if $valueToCheck equals it
92
     * @param mixed                 $valueToCheck   the value to check against $valueToThrowOn
93
     * @param null|string|Exception $exception      null, a fully qualified exception class name, string for an
94
     *                                              Exception message, or an Exception.  The fully qualified exception
95
     *                                              class name could also be an alias in getExceptionAliases()
96
     * @param array|null            $exceptionArgs  arguments to pass to a new instance of $exception. If using this
97
     *                                              parameter make sure these arguments match the constructor for an
98
     *                                              exception of type $exception.
99
     *
100
     * @return mixed returns $valueToCheck
101
     *
102
     * @throws Exception if $valueToThrowOn === $valueToCheck
103
     * @throws InvalidArgumentException if $exception was not null, a string, or an Exception
104
     */
105 View Code Duplication
    public static function ensureNot($valueToThrowOn, $valueToCheck, $exception = null, array $exceptionArgs = null)
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...
106
    {
107
        if ($valueToThrowOn === $valueToCheck) {
108
            throw self::buildException($exception ?: "'{$valueToThrowOn}' equals '{$valueToCheck}'", $exceptionArgs);
109
        }
110
111
        return $valueToCheck;
112
    }
113
114
    /**
115
     * Helper method to return exception created from ensure[Not] call input.
116
     *
117
     * @param mixed      $exception     Null, a fully qualified exception class name, string for an Exception message,
118
     *                                  or an Exception.  The fully qualified exception class name could also be an
119
     *                                  alias in getExceptionAliases()
120
     * @param array|null $exceptionArgs Arguments to pass to a new instance of $exception. If using this parameter make
121
     *                                  sure these arguments match the constructor for an exception of type $exception.
122
     *
123
     * @return Throwable
124
     *
125
     * @throws ReflectionException
126
     */
127
    private static function buildException($exception, array $exceptionArgs = null) : Throwable
128
    {
129
        if ($exception instanceof Exception) {
130
            return $exception;
131
        }
132
133
        if (!is_string($exception)) {
134
            throw new InvalidArgumentException('$exception was not null, a string, or an Exception');
135
        }
136
137
        if (empty($exceptionArgs)) {
138
            return new Exception($exception);
139
        }
140
141
        if (array_key_exists($exception, self::$exceptionAliases)) {
142
            $exception = self::$exceptionAliases[$exception];
143
        }
144
145
        return (new ReflectionClass($exception))->newInstanceArgs($exceptionArgs);
146
    }
147
148
    /**
149
     * Throws a new ErrorException based on the error information provided. To be
150
     * used as a callback for @see set_error_handler()
151
     *
152
     * @param int    $level   The level of the exception.
153
     * @param string $message The message the exception will give.
154
     * @param string $file    The file that the error occurred in.
155
     * @param string $line    The line that the exception occurred upon.
156
     *
157
     * @return bool false
158
     *
159
     * @throws ErrorException
160
     */
161
    public static function raiseException(int $level, string $message, string $file = null, string $line = null) : bool
162
    {
163
        if (error_reporting() === 0) {
164
            return false;
165
        }
166
167
        throw new ErrorException($message, 0, $level, $file, $line);
168
    }
169
170
    /**
171
     * Throws an exception if specified variables are not of given types.
172
     *
173
     * @param array $typesToVariables like ['string' => [$var1, $var2], 'int' => [$var1, $var2]] or
174
     *                                ['string' => $var1, 'integer' => [1, $var2]]. Supported types are the suffixes
175
     *                                of the is_* functions such as string for is_string and int for is_int
176
     * @param bool  $failOnWhitespace whether to fail strings if they are whitespace
177
     * @param bool  $allowNulls       whether to allow null values to pass through
178
     *
179
     * @return void
180
     *
181
     * @throws InvalidArgumentException if a key in $typesToVariables was not a string
182
     * @throws InvalidArgumentException if a key in $typesToVariables did not have an is_ function
183
     * @throws InvalidArgumentException if a variable is not of correct type
184
     * @throws InvalidArgumentException if a variable is whitespace and $failOnWhitespace is set
185
     */
186
    public static function throwIfNotType(
187
        array $typesToVariables,
188
        bool $failOnWhitespace = false,
189
        bool $allowNulls = false
190
    ) {
191
        foreach ($typesToVariables as $type => $variablesOrVariable) {
192
            self::handleTypesToVariables($failOnWhitespace, $allowNulls, $variablesOrVariable, $type);
193
        }
194
    }
195
196
    /**
197
     * Return the exception aliases.
198
     *
199
     * @return array array where keys are aliases and values are strings to a fully qualified exception class names.
200
     */
201
    public static function getExceptionAliases() : array
202
    {
203
        return self::$exceptionAliases;
204
    }
205
206
    /**
207
     * Set the exception aliases.
208
     *
209
     * @param array $aliases array where keys are aliases and values are strings to a fully qualified exception class
210
     *                       names.
211
     */
212
    public static function setExceptionAliases(array $aliases)
213
    {
214
        self::$exceptionAliases = $aliases;
215
    }
216
217
    private static function handleBoolCase(bool $allowNulls, array $variables)
218
    {
219
        foreach ($variables as $i => $variable) {
220
            //using the continue here not negative checks to make use of short cutting optimization.
221
            if ($variable === false || $variable === true || ($allowNulls && $variable === null)) {
222
                continue;
223
            }
224
225
            throw new InvalidArgumentException("variable at position '{$i}' was not a boolean");
226
        }
227
    }
228
229
    private static function handleNullCase(array $variables)
230
    {
231
        foreach ($variables as $i => $variable) {
232
            if ($variable !== null) {
233
                throw new InvalidArgumentException("variable at position '{$i}' was not null");
234
            }
235
        }
236
    }
237
238
    private static function handleStringCase(bool $failOnWhitespace, bool $allowNulls, array $variables, string $type)
239
    {
240
        foreach ($variables as $i => $variable) {
241
            if (is_string($variable)) {
242
                if ($failOnWhitespace && trim($variable) === '') {
243
                    throw new InvalidArgumentException("variable at position '{$i}' was whitespace");
244
                }
245
246
                continue;
247
            }
248
249
            if ($allowNulls && $variable === null) {
250
                continue;
251
            }
252
253
            throw new InvalidArgumentException("variable at position '{$i}' was not a '{$type}'");
254
        }
255
    }
256
257
    private static function handleDefaultCase(bool $allowNulls, string $type, array $variables)
258
    {
259
        $isFunction = "is_{$type}";
260
        foreach ($variables as $i => $variable) {
261
            if ($isFunction($variable) || ($allowNulls && $variable === null)) {
262
                continue;
263
            }
264
265
            throw new InvalidArgumentException("variable at position '{$i}' was not a '{$type}'");
266
        }
267
    }
268
269
    private static function handleTypesToVariables(
270
        bool $failOnWhitespace,
271
        bool $allowNulls,
272
        $variablesOrVariable,
273
        $type
274
    ) {
275
        $variables = [$variablesOrVariable];
276
        if (is_array($variablesOrVariable)) {
277
            $variables = $variablesOrVariable;
278
        }
279
280
        //cast ok since an integer won't match any of the cases.
281
        //the similar code in the cases is an optimization for those type where faster checks can be made.
282
        $typeString = (string)$type;
283
        if ($typeString === 'bool') {
284
            self::handleBoolCase($allowNulls, $variables);
285
            return;
286
        }
287
288
        if ($typeString === 'null') {
289
            self::handleNullCase($variables);
290
            return;
291
        }
292
293
        if ($typeString === 'string') {
294
            self::handleStringCase($failOnWhitespace, $allowNulls, $variables, $type);
295
            return;
296
        }
297
298
        $defaults = [
299
            'array',
300
            'callable',
301
            'double',
302
            'float',
303
            'int',
304
            'integer',
305
            'long',
306
            'numeric',
307
            'object',
308
            'real',
309
            'resource',
310
            'scalar',
311
        ];
312
        if (in_array($typeString, $defaults)) {
313
            self::handleDefaultCase($allowNulls, $type, $variables);
314
            return;
315
        }
316
317
        throw new InvalidArgumentException('a type was not one of the is_ functions');
318
    }
319
}
320