Failed Conditions
Pull Request — master (#118)
by Gert de
03:15
created

Assert   F

Complexity

Total Complexity 289

Size/Duplication

Total Lines 1512
Duplicated Lines 21.49 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 97.12%

Importance

Changes 0
Metric Value
wmc 289
lcom 1
cbo 0
dl 325
loc 1512
ccs 607
cts 625
cp 0.9712
rs 0.8
c 0
b 0
f 0

88 Methods

Rating   Name   Duplication   Size   Complexity  
A numeric() 0 9 3
A eq() 0 10 3
A isCallable() 0 9 3
A regex() 0 9 3
A alnum() 14 14 3
A string() 0 9 3
A stringNotEmpty() 0 5 1
A integer() 0 9 3
A integerish() 0 9 4
A float() 0 9 3
A natural() 0 9 4
A boolean() 0 9 3
A scalar() 0 9 3
A object() 0 9 3
A resource() 0 17 6
A isArray() 0 9 3
A isTraversable() 0 17 4
A isArrayAccessible() 9 9 4
A isCountable() 9 9 4
A isIterable() 9 9 4
A isInstanceOf() 0 10 3
A notInstanceOf() 0 10 3
A isInstanceOfAny() 0 14 4
A isEmpty() 0 9 3
A notEmpty() 0 9 3
A null() 0 9 3
A notNull() 0 8 3
A true() 0 9 3
A false() 0 9 3
A ip() 9 9 3
A ipv4() 9 9 3
A ipv6() 9 9 3
A email() 9 9 3
A uniqueValues() 0 15 4
A notEq() 0 9 3
A same() 0 10 3
A notSame() 0 9 3
A greaterThan() 0 10 3
A greaterThanEq() 0 10 3
A lessThan() 0 10 3
A lessThanEq() 0 10 3
A range() 11 11 4
A oneOf() 0 10 3
A contains() 10 10 3
A notContains() 10 10 3
A notWhitespaceOnly() 0 9 3
A startsWith() 10 10 3
A startsWithLetter() 0 18 4
A endsWith() 10 10 3
A notRegex() 0 11 3
A unicodeLetters() 11 11 3
A alpha() 14 14 3
A digits() 14 14 3
A lower() 14 14 3
A upper() 14 14 3
A length() 0 10 3
A minLength() 0 10 3
A maxLength() 0 10 3
A lengthBetween() 13 13 4
A fileExists() 11 11 3
A file() 11 11 3
A directory() 11 11 3
A readable() 0 9 3
A writable() 0 9 3
A classExists() 0 9 3
A subclassOf() 0 10 3
A interfaceExists() 0 9 3
A implementsInterface() 10 10 3
A propertyExists() 9 9 3
A propertyNotExists() 9 9 3
A methodExists() 9 9 3
A methodNotExists() 9 9 3
A keyExists() 9 9 4
A keyNotExists() 9 9 4
A count() 0 8 2
A minCount() 10 10 3
A maxCount() 10 10 3
A countBetween() 0 13 4
A isList() 0 8 5
A isMap() 0 14 5
A uuid() 0 17 4
B throws() 0 26 6
A __callStatic() 0 28 5
B valueToString() 0 36 9
A typeToString() 0 4 2
A strlen() 0 12 3
A reportInvalidArgument() 0 4 1
A __construct() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Assert often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Assert, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the webmozart/assert package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webmozart\Assert;
13
14
use ArrayAccess;
15
use BadMethodCallException;
16
use Closure;
17
use Countable;
18
use Exception;
19
use InvalidArgumentException;
20
use Throwable;
21
use Traversable;
22
23
/**
24
 * Efficient assertions to validate the input/output of your methods.
25
 *
26
 * @method static void nullOrString($value, $message = '')
27
 * @method static void nullOrStringNotEmpty($value, $message = '')
28
 * @method static void nullOrInteger($value, $message = '')
29
 * @method static void nullOrIntegerish($value, $message = '')
30
 * @method static void nullOrFloat($value, $message = '')
31
 * @method static void nullOrNumeric($value, $message = '')
32
 * @method static void nullOrNatural($value, $message = '')
33
 * @method static void nullOrBoolean($value, $message = '')
34
 * @method static void nullOrScalar($value, $message = '')
35
 * @method static void nullOrObject($value, $message = '')
36
 * @method static void nullOrResource($value, $type = null, $message = '')
37
 * @method static void nullOrIsCallable($value, $message = '')
38
 * @method static void nullOrIsArray($value, $message = '')
39
 * @method static void nullOrIsTraversable($value, $message = '')
40
 * @method static void nullOrIsArrayAccessible($value, $message = '')
41
 * @method static void nullOrIsCountable($value, $message = '')
42
 * @method static void nullOrIsIterable($value, $message = '')
43
 * @method static void nullOrIsInstanceOf($value, $class, $message = '')
44
 * @method static void nullOrNotInstanceOf($value, $class, $message = '')
45
 * @method static void nullOrIsInstanceOfAny($value, $classes, $message = '')
46
 * @method static void nullOrIsEmpty($value, $message = '')
47
 * @method static void nullOrNotEmpty($value, $message = '')
48
 * @method static void nullOrTrue($value, $message = '')
49
 * @method static void nullOrFalse($value, $message = '')
50
 * @method static void nullOrIp($value, $message = '')
51
 * @method static void nullOrIpv4($value, $message = '')
52
 * @method static void nullOrIpv6($value, $message = '')
53
 * @method static void nullOrEmail($value, $message = '')
54
 * @method static void nullOrUniqueValues($values, $message = '')
55
 * @method static void nullOrEq($value, $expect, $message = '')
56
 * @method static void nullOrNotEq($value, $expect, $message = '')
57
 * @method static void nullOrSame($value, $expect, $message = '')
58
 * @method static void nullOrNotSame($value, $expect, $message = '')
59
 * @method static void nullOrGreaterThan($value, $limit, $message = '')
60
 * @method static void nullOrGreaterThanEq($value, $limit, $message = '')
61
 * @method static void nullOrLessThan($value, $limit, $message = '')
62
 * @method static void nullOrLessThanEq($value, $limit, $message = '')
63
 * @method static void nullOrRange($value, $min, $max, $message = '')
64
 * @method static void nullOrOneOf($value, $values, $message = '')
65
 * @method static void nullOrContains($value, $subString, $message = '')
66
 * @method static void nullOrNotContains($value, $subString, $message = '')
67
 * @method static void nullOrNotWhitespaceOnly($value, $message = '')
68
 * @method static void nullOrStartsWith($value, $prefix, $message = '')
69
 * @method static void nullOrStartsWithLetter($value, $message = '')
70
 * @method static void nullOrEndsWith($value, $suffix, $message = '')
71
 * @method static void nullOrRegex($value, $pattern, $message = '')
72
 * @method static void nullOrNotRegex($value, $pattern, $message = '')
73
 * @method static void nullOrUnicodeLetters($value, $message = '')
74
 * @method static void nullOrAlpha($value, $message = '')
75
 * @method static void nullOrDigits($value, $message = '')
76
 * @method static void nullOrAlnum($value, $message = '')
77
 * @method static void nullOrLower($value, $message = '')
78
 * @method static void nullOrUpper($value, $message = '')
79
 * @method static void nullOrLength($value, $length, $message = '')
80
 * @method static void nullOrMinLength($value, $min, $message = '')
81
 * @method static void nullOrMaxLength($value, $max, $message = '')
82
 * @method static void nullOrLengthBetween($value, $min, $max, $message = '')
83
 * @method static void nullOrFileExists($value, $message = '')
84
 * @method static void nullOrFile($value, $message = '')
85
 * @method static void nullOrDirectory($value, $message = '')
86
 * @method static void nullOrReadable($value, $message = '')
87
 * @method static void nullOrWritable($value, $message = '')
88
 * @method static void nullOrClassExists($value, $message = '')
89
 * @method static void nullOrSubclassOf($value, $class, $message = '')
90
 * @method static void nullOrInterfaceExists($value, $message = '')
91
 * @method static void nullOrImplementsInterface($value, $interface, $message = '')
92
 * @method static void nullOrPropertyExists($value, $property, $message = '')
93
 * @method static void nullOrPropertyNotExists($value, $property, $message = '')
94
 * @method static void nullOrMethodExists($value, $method, $message = '')
95
 * @method static void nullOrMethodNotExists($value, $method, $message = '')
96
 * @method static void nullOrKeyExists($value, $key, $message = '')
97
 * @method static void nullOrKeyNotExists($value, $key, $message = '')
98
 * @method static void nullOrCount($value, $key, $message = '')
99
 * @method static void nullOrMinCount($value, $min, $message = '')
100
 * @method static void nullOrMaxCount($value, $max, $message = '')
101
 * @method static void nullOrIsList($value, $message = '')
102
 * @method static void nullOrIsMap($value, $message = '')
103
 * @method static void nullOrCountBetween($value, $min, $max, $message = '')
104
 * @method static void nullOrUuid($values, $message = '')
105
 * @method static void nullOrThrows($expression, $class = 'Exception', $message = '')
106
 * @method static void allString($values, $message = '')
107
 * @method static void allStringNotEmpty($values, $message = '')
108
 * @method static void allInteger($values, $message = '')
109
 * @method static void allIntegerish($values, $message = '')
110
 * @method static void allFloat($values, $message = '')
111
 * @method static void allNumeric($values, $message = '')
112
 * @method static void allNatural($values, $message = '')
113
 * @method static void allBoolean($values, $message = '')
114
 * @method static void allScalar($values, $message = '')
115
 * @method static void allObject($values, $message = '')
116
 * @method static void allResource($values, $type = null, $message = '')
117
 * @method static void allIsCallable($values, $message = '')
118
 * @method static void allIsArray($values, $message = '')
119
 * @method static void allIsTraversable($values, $message = '')
120
 * @method static void allIsArrayAccessible($values, $message = '')
121
 * @method static void allIsCountable($values, $message = '')
122
 * @method static void allIsIterable($values, $message = '')
123
 * @method static void allIsInstanceOf($values, $class, $message = '')
124
 * @method static void allNotInstanceOf($values, $class, $message = '')
125
 * @method static void allIsInstanceOfAny($values, $classes, $message = '')
126
 * @method static void allNull($values, $message = '')
127
 * @method static void allNotNull($values, $message = '')
128
 * @method static void allIsEmpty($values, $message = '')
129
 * @method static void allNotEmpty($values, $message = '')
130
 * @method static void allTrue($values, $message = '')
131
 * @method static void allFalse($values, $message = '')
132
 * @method static void allIp($values, $message = '')
133
 * @method static void allIpv4($values, $message = '')
134
 * @method static void allIpv6($values, $message = '')
135
 * @method static void allEmail($values, $message = '')
136
 * @method static void allUniqueValues($values, $message = '')
137
 * @method static void allEq($values, $expect, $message = '')
138
 * @method static void allNotEq($values, $expect, $message = '')
139
 * @method static void allSame($values, $expect, $message = '')
140
 * @method static void allNotSame($values, $expect, $message = '')
141
 * @method static void allGreaterThan($values, $limit, $message = '')
142
 * @method static void allGreaterThanEq($values, $limit, $message = '')
143
 * @method static void allLessThan($values, $limit, $message = '')
144
 * @method static void allLessThanEq($values, $limit, $message = '')
145
 * @method static void allRange($values, $min, $max, $message = '')
146
 * @method static void allOneOf($values, $values, $message = '')
147
 * @method static void allContains($values, $subString, $message = '')
148
 * @method static void allNotContains($values, $subString, $message = '')
149
 * @method static void allNotWhitespaceOnly($values, $message = '')
150
 * @method static void allStartsWith($values, $prefix, $message = '')
151
 * @method static void allStartsWithLetter($values, $message = '')
152
 * @method static void allEndsWith($values, $suffix, $message = '')
153
 * @method static void allRegex($values, $pattern, $message = '')
154
 * @method static void allNotRegex($values, $pattern, $message = '')
155
 * @method static void allUnicodeLetters($values, $message = '')
156
 * @method static void allAlpha($values, $message = '')
157
 * @method static void allDigits($values, $message = '')
158
 * @method static void allAlnum($values, $message = '')
159
 * @method static void allLower($values, $message = '')
160
 * @method static void allUpper($values, $message = '')
161
 * @method static void allLength($values, $length, $message = '')
162
 * @method static void allMinLength($values, $min, $message = '')
163
 * @method static void allMaxLength($values, $max, $message = '')
164
 * @method static void allLengthBetween($values, $min, $max, $message = '')
165
 * @method static void allFileExists($values, $message = '')
166
 * @method static void allFile($values, $message = '')
167
 * @method static void allDirectory($values, $message = '')
168
 * @method static void allReadable($values, $message = '')
169
 * @method static void allWritable($values, $message = '')
170
 * @method static void allClassExists($values, $message = '')
171
 * @method static void allSubclassOf($values, $class, $message = '')
172
 * @method static void allInterfaceExists($values, $message = '')
173
 * @method static void allImplementsInterface($values, $interface, $message = '')
174
 * @method static void allPropertyExists($values, $property, $message = '')
175
 * @method static void allPropertyNotExists($values, $property, $message = '')
176
 * @method static void allMethodExists($values, $method, $message = '')
177
 * @method static void allMethodNotExists($values, $method, $message = '')
178
 * @method static void allKeyExists($values, $key, $message = '')
179
 * @method static void allKeyNotExists($values, $key, $message = '')
180
 * @method static void allCount($values, $key, $message = '')
181
 * @method static void allMinCount($values, $min, $message = '')
182
 * @method static void allMaxCount($values, $max, $message = '')
183
 * @method static void allCountBetween($values, $min, $max, $message = '')
184
 * @method static void allIsList($values, $message = '')
185
 * @method static void allIsMap($values, $message = '')
186
 * @method static void allUuid($values, $message = '')
187
 * @method static void allThrows($expressions, $class = 'Exception', $message = '')
188
 *
189
 * @since  1.0
190
 *
191
 * @author Bernhard Schussek <[email protected]>
192
 */
193
class Assert
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
194
{
195
    /**
196
     * @psalm-assert string $value
197
     *
198
     * @param mixed $value
199
     * @param string $message
200
     */
201 122
    public static function string($value, $message = '')
202
    {
203 122
        if (!\is_string($value)) {
204 14
            static::reportInvalidArgument(\sprintf(
205 14
                $message ?: 'Expected a string. Got: %s',
206 14
                static::typeToString($value)
207
            ));
208
        }
209 108
    }
210
211
    /**
212
     * @psalm-assert string $value
213
     *
214
     * @param mixed $value
215
     * @param string $message
216
     */
217 16
    public static function stringNotEmpty($value, $message = '')
218
    {
219 16
        static::string($value, $message);
220 12
        static::notEq($value, '', $message);
221 8
    }
222
223
    /**
224
     * @psalm-assert int $value
225
     *
226
     * @param mixed $value
227
     * @param string $message
228
     */
229 17
    public static function integer($value, $message = '')
230
    {
231 17
        if (!\is_int($value)) {
232 13
            static::reportInvalidArgument(\sprintf(
233 13
                $message ?: 'Expected an integer. Got: %s',
234 13
                static::typeToString($value)
235
            ));
236
        }
237 4
    }
238
239
    /**
240
     * @psalm-assert numeric
241
     *
242
     * @param mixed $value
243
     * @param string $message
244
     */
245 16
    public static function integerish($value, $message = '')
246
    {
247 16
        if (!\is_numeric($value) || $value != (int) $value) {
248 4
            static::reportInvalidArgument(\sprintf(
249 4
                $message ?: 'Expected an integerish value. Got: %s',
250 4
                static::typeToString($value)
251
            ));
252
        }
253 12
    }
254
255
    /**
256
     * @psalm-assert float $value
257
     *
258
     * @param mixed $value
259
     * @param string $message
260
     */
261 16
    public static function float($value, $message = '')
262
    {
263 16
        if (!\is_float($value)) {
264 8
            static::reportInvalidArgument(\sprintf(
265 8
                $message ?: 'Expected a float. Got: %s',
266 8
                static::typeToString($value)
267
            ));
268
        }
269 8
    }
270
271
    /**
272
     * @psalm-assert numeric $value
273
     *
274
     * @param mixed $value
275
     * @param string $message
276
     */
277 20
    public static function numeric($value, $message = '')
278
    {
279 20
        if (!\is_numeric($value)) {
280 4
            static::reportInvalidArgument(\sprintf(
281 4
                $message ?: 'Expected a numeric. Got: %s',
282 4
                static::typeToString($value)
283
            ));
284
        }
285 16
    }
286
287
    /**
288
     * @psalm-assert int $value
289
     *
290
     * @param mixed $value
291
     * @param string $message
292
     */
293 24
    public static function natural($value, $message = '')
294
    {
295 24
        if (!\is_int($value) || $value < 0) {
296 16
            static::reportInvalidArgument(\sprintf(
297 16
                $message ?: 'Expected a non-negative integer. Got %s',
298 16
                static::valueToString($value)
299
            ));
300
        }
301 8
    }
302
303
    /**
304
     * @psalm-assert bool $value
305
     *
306
     * @param mixed $value
307
     * @param string $message
308
     */
309 16
    public static function boolean($value, $message = '')
310
    {
311 16
        if (!\is_bool($value)) {
312 8
            static::reportInvalidArgument(\sprintf(
313 8
                $message ?: 'Expected a boolean. Got: %s',
314 8
                static::typeToString($value)
315
            ));
316
        }
317 8
    }
318
319
    /**
320
     * @psalm-assert scalar $value
321
     *
322
     * @param mixed $value
323
     * @param string $message
324
     */
325 23
    public static function scalar($value, $message = '')
326
    {
327 23
        if (!\is_scalar($value)) {
328 11
            static::reportInvalidArgument(\sprintf(
329 11
                $message ?: 'Expected a scalar. Got: %s',
330 11
                static::typeToString($value)
331
            ));
332
        }
333 12
    }
334
335
    /**
336
     * @psalm-assert object $value
337
     *
338
     * @param mixed$value
339
     * @param string $message
340
     */
341 23
    public static function object($value, $message = '')
342
    {
343 23
        if (!\is_object($value)) {
344 15
            static::reportInvalidArgument(\sprintf(
345 15
                $message ?: 'Expected an object. Got: %s',
346 15
                static::typeToString($value)
347
            ));
348
        }
349 8
    }
350
351
    /**
352
     * @psalm-assert resource $value
353
     *
354
     * @param mixed $value
355
     * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
356
     * @param string $message
357
     */
358 16
    public static function resource($value, $type = null, $message = '')
359
    {
360 16
        if (!\is_resource($value)) {
361 4
            static::reportInvalidArgument(\sprintf(
362 4
                $message ?: 'Expected a resource. Got: %s',
363 4
                static::typeToString($value)
364
            ));
365
        }
366
367 12
        if ($type && $type !== \get_resource_type($value)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
368 4
            static::reportInvalidArgument(\sprintf(
369 4
                $message ?: 'Expected a resource of type %2$s. Got: %s',
370 4
                static::typeToString($value),
371 4
                $type
372
            ));
373
        }
374 8
    }
375
376
    /**
377
     * @psalm-assert callable $value
378
     *
379
     * @param mixed $value
380
     * @param string $message
381
     */
382 20
    public static function isCallable($value, $message = '')
383
    {
384 20
        if (!\is_callable($value)) {
385 8
            static::reportInvalidArgument(\sprintf(
386 8
                $message ?: 'Expected a callable. Got: %s',
387 8
                static::typeToString($value)
388
            ));
389
        }
390 12
    }
391
392
    /**
393
     * @psalm-assert array $value
394
     *
395
     * @param mixed $value
396
     * @param string $message
397
     */
398 20
    public static function isArray($value, $message = '')
399
    {
400 20
        if (!\is_array($value)) {
401 12
            static::reportInvalidArgument(\sprintf(
402 12
                $message ?: 'Expected an array. Got: %s',
403 12
                static::typeToString($value)
404
            ));
405
        }
406 8
    }
407
408
    /**
409
     * @deprecated use "isIterable" or "isInstanceOf" instead
410
     *
411
     * @psalm-assert iterable $value
412
     *
413
     * @param mixed $value
414
     * @param string $message
415
     */
416 20
    public static function isTraversable($value, $message = '')
417
    {
418 20
        @\trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
419 20
            \sprintf(
420 20
                'The "%s" assertion is deprecated. You should stop using it, as it will soon be removed in 2.0 version. Use "isIterable" or "isInstanceOf" instead.',
421 20
                __METHOD__
422
            ),
423 20
            \E_USER_DEPRECATED
424
        );
425
426 20
        if (!\is_array($value) && !($value instanceof Traversable)) {
427 8
            static::reportInvalidArgument(\sprintf(
428 8
                $message ?: 'Expected a traversable. Got: %s',
429 8
                static::typeToString($value)
430
            ));
431
        }
432 12
    }
433
434
    /**
435
     * @param mixed $value
436
     * @param string $message
437
     */
438 20 View Code Duplication
    public static function isArrayAccessible($value, $message = '')
439
    {
440 20
        if (!\is_array($value) && !($value instanceof ArrayAccess)) {
441 8
            static::reportInvalidArgument(\sprintf(
442 8
                $message ?: 'Expected an array accessible. Got: %s',
443 8
                static::typeToString($value)
444
            ));
445
        }
446 12
    }
447
448
    /**
449
     * @psalm-assert countable $value
450
     *
451
     * @param mixed $value
452
     * @param string $message
453
     */
454 24 View Code Duplication
    public static function isCountable($value, $message = '')
455
    {
456 24
        if (!\is_array($value) && !($value instanceof Countable)) {
457 12
            static::reportInvalidArgument(\sprintf(
458 12
                $message ?: 'Expected a countable. Got: %s',
459 12
                static::typeToString($value)
460
            ));
461
        }
462 12
    }
463
464
    /**
465
     * @psalm-assert iterable $value
466
     *
467
     * @param mixed $value
468
     * @param string $message
469
     */
470 878 View Code Duplication
    public static function isIterable($value, $message = '')
471
    {
472 878
        if (!\is_array($value) && !($value instanceof Traversable)) {
473 8
            static::reportInvalidArgument(\sprintf(
474 8
                $message ?: 'Expected an iterable. Got: %s',
475 8
                static::typeToString($value)
476
            ));
477
        }
478 874
    }
479
480
    /**
481
     * @psalm-template ExpectedType of object
482
     * @psalm-param class-string<ExpectedType> $class
483
     * @psalm-assert ExpectedType $value
484
     *
485
     * @param mixed $value
486
     * @param string|object $class
487
     * @param string $message
488
     */
489 16
    public static function isInstanceOf($value, $class, $message = '')
490
    {
491 16
        if (!($value instanceof $class)) {
492 12
            static::reportInvalidArgument(\sprintf(
493 12
                $message ?: 'Expected an instance of %2$s. Got: %s',
494 12
                static::typeToString($value),
495 12
                $class
496
            ));
497
        }
498 4
    }
499
500
    /**
501
     * @psalm-template ExpectedType of object
502
     * @psalm-param class-string<ExpectedType> $class
503
     * @psalm-assert !ExpectedType $value
504
     *
505
     * @param mixed $value
506
     * @param string|object $class
507
     * @param string $message
508
     */
509 16
    public static function notInstanceOf($value, $class, $message = '')
510
    {
511 16
        if ($value instanceof $class) {
512 4
            static::reportInvalidArgument(\sprintf(
513 4
                $message ?: 'Expected an instance other than %2$s. Got: %s',
514 4
                static::typeToString($value),
515 4
                $class
516
            ));
517
        }
518 12
    }
519
520
    /**
521
     * @psalm-template ExpectedType
522
     * @psalm-param array<class-string<ExpectedType>|ExpectedType> $classes
523
     * @psalm-assert ExpectedType $value
524
     *
525
     * @param mixed $value
526
     * @param array<object|string> $classes
527
     * @param string $message
528
     */
529 20
    public static function isInstanceOfAny($value, array $classes, $message = '')
530
    {
531 20
        foreach ($classes as $class) {
532 20
            if ($value instanceof $class) {
533 8
                return;
534
            }
535
        }
536
537 12
        static::reportInvalidArgument(\sprintf(
538 12
            $message ?: 'Expected an instance of any of %2$s. Got: %s',
539 12
            static::typeToString($value),
540 12
            \implode(', ', \array_map(array('static', 'valueToString'), $classes))
541
        ));
542
    }
543
544
    /**
545
     * @psalm-assert empty $value
546
     *
547
     * @param mixed $value
548
     * @param string $message
549
     */
550 23
    public static function isEmpty($value, $message = '')
551
    {
552 23
        if (!empty($value)) {
553 8
            static::reportInvalidArgument(\sprintf(
554 8
                $message ?: 'Expected an empty value. Got: %s',
555 8
                static::valueToString($value)
556
            ));
557
        }
558 15
    }
559
560
    /**
561
     * @psalm-assert !empty $value
562
     *
563
     * @param mixed $value
564
     * @param string $message
565
     */
566 23
    public static function notEmpty($value, $message = '')
567
    {
568 23
        if (empty($value)) {
569 15
            static::reportInvalidArgument(\sprintf(
570 15
                $message ?: 'Expected a non-empty value. Got: %s',
571 15
                static::valueToString($value)
572
            ));
573
        }
574 8
    }
575
576
    /**
577
     * @psalm-assert null $value
578
     *
579
     * @param mixed $value
580
     * @param string $message
581
     */
582 11
    public static function null($value, $message = '')
583
    {
584 11
        if (null !== $value) {
585 8
            static::reportInvalidArgument(\sprintf(
586 8
                $message ?: 'Expected null. Got: %s',
587 8
                static::valueToString($value)
588
            ));
589
        }
590 3
    }
591
592
    /**
593
     * @psalm-assert !null $value
594
     *
595
     * @param mixed $value
596
     * @param string $message
597
     */
598 11
    public static function notNull($value, $message = '')
599
    {
600 11
        if (null === $value) {
601 3
            static::reportInvalidArgument(
602 3
                $message ?: 'Expected a value other than null.'
603
            );
604
        }
605 8
    }
606
607
    /**
608
     * @psalm-assert true $value
609
     *
610
     * @param mixed $value
611
     * @param string $message
612
     */
613 15
    public static function true($value, $message = '')
614
    {
615 15
        if (true !== $value) {
616 11
            static::reportInvalidArgument(\sprintf(
617 11
                $message ?: 'Expected a value to be true. Got: %s',
618 11
                static::valueToString($value)
619
            ));
620
        }
621 4
    }
622
623
    /**
624
     * @psalm-assert false $value
625
     *
626
     * @param mixed$value
627
     * @param string $message
628
     */
629 19
    public static function false($value, $message = '')
630
    {
631 19
        if (false !== $value) {
632 15
            static::reportInvalidArgument(\sprintf(
633 15
                $message ?: 'Expected a value to be false. Got: %s',
634 15
                static::valueToString($value)
635
            ));
636
        }
637 4
    }
638
639
    /**
640
     * @param mixed $value
641
     * @param string $message
642
     */
643 47 View Code Duplication
    public static function ip($value, $message = '')
644
    {
645 47
        if (false === \filter_var($value, \FILTER_VALIDATE_IP)) {
646 19
            static::reportInvalidArgument(\sprintf(
647 19
                $message ?: 'Expected a value to be an IP. Got: %s',
648 19
                static::valueToString($value)
649
            ));
650
        }
651 28
    }
652
653
    /**
654
     * @param mixed $value
655
     * @param string $message
656
     */
657 47 View Code Duplication
    public static function ipv4($value, $message = '')
658
    {
659 47
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
660 35
            static::reportInvalidArgument(\sprintf(
661 35
                $message ?: 'Expected a value to be an IPv4. Got: %s',
662 35
                static::valueToString($value)
663
            ));
664
        }
665 12
    }
666
667
    /**
668
     * @param mixed $value
669
     * @param string $message
670
     */
671 47 View Code Duplication
    public static function ipv6($value, $message = '')
672
    {
673 47
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
674 31
            static::reportInvalidArgument(\sprintf(
675 31
                $message ?: 'Expected a value to be an IPv6. Got %s',
676 31
                static::valueToString($value)
677
            ));
678
        }
679 16
    }
680
681
    /**
682
     * @param mixed $value
683
     * @param string $message
684
     */
685 16 View Code Duplication
    public static function email($value, $message = '')
686
    {
687 16
        if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) {
688 12
            static::reportInvalidArgument(\sprintf(
689 12
                $message ?: 'Expected a value to be a valid e-mail address. Got %s',
690 12
                static::valueToString($value)
691
            ));
692
        }
693 4
    }
694
695
    /**
696
     * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion.
697
     *
698
     * @param array $values
699
     * @param string $message
700
     */
701 12
    public static function uniqueValues(array $values, $message = '')
702
    {
703 12
        $allValues = \count($values);
704 12
        $uniqueValues = \count(\array_unique($values));
705
706 12
        if ($allValues !== $uniqueValues) {
707 8
            $difference = $allValues - $uniqueValues;
708
709 8
            static::reportInvalidArgument(\sprintf(
710 8
                $message ?: 'Expected an array of unique values, but %s of them %s duplicated',
711 8
                $difference,
712 8
                (1 === $difference ? 'is' : 'are')
713
            ));
714
        }
715 4
    }
716
717
    /**
718
     * @param mixed $value
719
     * @param mixed $expect
720
     * @param string $message
721
     */
722 33
    public static function eq($value, $expect, $message = '')
723
    {
724 33
        if ($expect != $value) {
725 17
            static::reportInvalidArgument(\sprintf(
726 17
                $message ?: 'Expected a value equal to %2$s. Got: %s',
727 17
                static::valueToString($value),
728 17
                static::valueToString($expect)
729
            ));
730
        }
731 16
    }
732
733
    /**
734
     * @param mixed $value
735
     * @param mixed $expect
736
     * @param string $message
737
     */
738 28
    public static function notEq($value, $expect, $message = '')
739
    {
740 28
        if ($expect == $value) {
741 16
            static::reportInvalidArgument(\sprintf(
742 16
                $message ?: 'Expected a different value than %s.',
743 16
                static::valueToString($expect)
744
            ));
745
        }
746 12
    }
747
748
    /**
749
     * @psalm-template ExpectedType
750
     * @psalm-param ExpectedType $expect
751
     * @psalm-assert =ExpectedType $value
752
     *
753
     * @param mixed $value
754
     * @param mixed $expect
755
     * @param string $message
756
     */
757 16
    public static function same($value, $expect, $message = '')
758
    {
759 16
        if ($expect !== $value) {
760 12
            static::reportInvalidArgument(\sprintf(
761 12
                $message ?: 'Expected a value identical to %2$s. Got: %s',
762 12
                static::valueToString($value),
763 12
                static::valueToString($expect)
764
            ));
765
        }
766 4
    }
767
768
    /**
769
     * @param mixed $value
770
     * @param mixed $expect
771
     * @param string $message
772
     */
773 16
    public static function notSame($value, $expect, $message = '')
774
    {
775 16
        if ($expect === $value) {
776 4
            static::reportInvalidArgument(\sprintf(
777 4
                $message ?: 'Expected a value not identical to %s.',
778 4
                static::valueToString($expect)
779
            ));
780
        }
781 12
    }
782
783
    /**
784
     * @param mixed $value
785
     * @param mixed $limit
786
     * @param string $message
787
     */
788 8
    public static function greaterThan($value, $limit, $message = '')
789
    {
790 8
        if ($value <= $limit) {
791 4
            static::reportInvalidArgument(\sprintf(
792 4
                $message ?: 'Expected a value greater than %2$s. Got: %s',
793 4
                static::valueToString($value),
794 4
                static::valueToString($limit)
795
            ));
796
        }
797 4
    }
798
799
    /**
800
     * @param mixed $value
801
     * @param mixed $limit
802
     * @param string $message
803
     */
804 12
    public static function greaterThanEq($value, $limit, $message = '')
805
    {
806 12
        if ($value < $limit) {
807 4
            static::reportInvalidArgument(\sprintf(
808 4
                $message ?: 'Expected a value greater than or equal to %2$s. Got: %s',
809 4
                static::valueToString($value),
810 4
                static::valueToString($limit)
811
            ));
812
        }
813 8
    }
814
815
    /**
816
     * @param mixed $value
817
     * @param mixed $limit
818
     * @param string $message
819
     */
820 8
    public static function lessThan($value, $limit, $message = '')
821
    {
822 8
        if ($value >= $limit) {
823 4
            static::reportInvalidArgument(\sprintf(
824 4
                $message ?: 'Expected a value less than %2$s. Got: %s',
825 4
                static::valueToString($value),
826 4
                static::valueToString($limit)
827
            ));
828
        }
829 4
    }
830
831
    /**
832
     * @param mixed $value
833
     * @param mixed $limit
834
     * @param string $message
835
     */
836 12
    public static function lessThanEq($value, $limit, $message = '')
837
    {
838 12
        if ($value > $limit) {
839 4
            static::reportInvalidArgument(\sprintf(
840 4
                $message ?: 'Expected a value less than or equal to %2$s. Got: %s',
841 4
                static::valueToString($value),
842 4
                static::valueToString($limit)
843
            ));
844
        }
845 8
    }
846
847
    /**
848
     * Inclusive range, so Assert::(3, 3, 5) passes.
849
     *
850
     * @param mixed $value
851
     * @param mixed min
852
     * @param mixed max
853
     * @param string $message
854
     */
855 16 View Code Duplication
    public static function range($value, $min, $max, $message = '')
856
    {
857 16
        if ($value < $min || $value > $max) {
858 8
            static::reportInvalidArgument(\sprintf(
859 8
                $message ?: 'Expected a value between %2$s and %3$s. Got: %s',
860 8
                static::valueToString($value),
861 8
                static::valueToString($min),
862 8
                static::valueToString($max)
863
            ));
864
        }
865 8
    }
866
867
    /**
868
     * Does strict comparison, so Assert::oneOf(3, ['3']) does not pass the assertion.
869
     *
870
     * @psalm-template ExpectedType
871
     * @psalm-param array<ExpectedType> $values
872
     * @psalm-assert ExpectedType $value
873
     *
874
     * @param mixed $value
875
     * @param array $values
876
     * @param string $message
877
     */
878 8
    public static function oneOf($value, array $values, $message = '')
879
    {
880 8
        if (!\in_array($value, $values, true)) {
881 4
            static::reportInvalidArgument(\sprintf(
882 4
                $message ?: 'Expected one of: %2$s. Got: %s',
883 4
                static::valueToString($value),
884 4
                \implode(', ', \array_map(array('static', 'valueToString'), $values))
885
            ));
886
        }
887 4
    }
888
889
    /**
890
     * @param mixed $value
891
     * @param string $subString
892
     * @param string $message
893
     */
894 80 View Code Duplication
    public static function contains($value, $subString, $message = '')
895
    {
896 80
        if (false === \strpos($value, $subString)) {
897 32
            static::reportInvalidArgument(\sprintf(
898 32
                $message ?: 'Expected a value to contain %2$s. Got: %s',
899 32
                static::valueToString($value),
900 32
                static::valueToString($subString)
901
            ));
902
        }
903 48
    }
904
905
    /**
906
     * @param mixed $value
907
     * @param string $subString
908
     * @param string $message
909
     */
910 80 View Code Duplication
    public static function notContains($value, $subString, $message = '')
911
    {
912 80
        if (false !== \strpos($value, $subString)) {
913 48
            static::reportInvalidArgument(\sprintf(
914 48
                $message ?: '%2$s was not expected to be contained in a value. Got: %s',
915 48
                static::valueToString($value),
916 48
                static::valueToString($subString)
917
            ));
918
        }
919 32
    }
920
921
    /**
922
     * @param mixed $value
923
     * @param string $message
924
     */
925 40
    public static function notWhitespaceOnly($value, $message = '')
926
    {
927 40
        if (\preg_match('/^\s*$/', $value)) {
928 24
            static::reportInvalidArgument(\sprintf(
929 24
                $message ?: 'Expected a non-whitespace string. Got: %s',
930 24
                static::valueToString($value)
931
            ));
932
        }
933 16
    }
934
935
    /**
936
     * @param mixed $value
937
     * @param string $prefix
938
     * @param string $message
939
     */
940 48 View Code Duplication
    public static function startsWith($value, $prefix, $message = '')
941
    {
942 48
        if (0 !== \strpos($value, $prefix)) {
943 32
            static::reportInvalidArgument(\sprintf(
944 32
                $message ?: 'Expected a value to start with %2$s. Got: %s',
945 32
                static::valueToString($value),
946 32
                static::valueToString($prefix)
947
            ));
948
        }
949 16
    }
950
951
    /**
952
     * @param mixed $value
953
     * @param string $message
954
     */
955 24
    public static function startsWithLetter($value, $message = '')
956
    {
957 24
        $valid = isset($value[0]);
958
959 24
        if ($valid) {
960 20
            $locale = \setlocale(LC_CTYPE, 0);
961 20
            \setlocale(LC_CTYPE, 'C');
962 20
            $valid = \ctype_alpha($value[0]);
963 20
            \setlocale(LC_CTYPE, $locale);
964
        }
965
966 24
        if (!$valid) {
967 12
            static::reportInvalidArgument(\sprintf(
968 12
                $message ?: 'Expected a value to start with a letter. Got: %s',
969 12
                static::valueToString($value)
970
            ));
971
        }
972 12
    }
973
974
    /**
975
     * @param mixed $value
976
     * @param string $suffix
977
     * @param string $message
978
     */
979 48 View Code Duplication
    public static function endsWith($value, $suffix, $message = '')
980
    {
981 48
        if ($suffix !== \substr($value, -\strlen($suffix))) {
982 32
            static::reportInvalidArgument(\sprintf(
983 32
                $message ?: 'Expected a value to end with %2$s. Got: %s',
984 32
                static::valueToString($value),
985 32
                static::valueToString($suffix)
986
            ));
987
        }
988 16
    }
989
990
    /**
991
     * @param mixed $value
992
     * @param mixed $pattern
993
     * @param string $message
994
     */
995 12
    public static function regex($value, $pattern, $message = '')
996
    {
997 12
        if (!\preg_match($pattern, $value)) {
998 8
            static::reportInvalidArgument(\sprintf(
999 8
                $message ?: 'The value %s does not match the expected pattern.',
1000 8
                static::valueToString($value)
1001
            ));
1002
        }
1003 4
    }
1004
1005
    /**
1006
     * @param mixed $value
1007
     * @param mixed $pattern
1008
     * @param string $message
1009
     */
1010 12
    public static function notRegex($value, $pattern, $message = '')
1011
    {
1012 12
        if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
1013 4
            static::reportInvalidArgument(\sprintf(
1014 4
                $message ?: 'The value %s matches the pattern %s (at offset %d).',
1015 4
                static::valueToString($value),
1016 4
                static::valueToString($pattern),
1017 4
                $matches[0][1]
1018
            ));
1019
        }
1020 8
    }
1021
1022
    /**
1023
     * @param mixed $value
1024
     * @param string $message
1025
     */
1026 28 View Code Duplication
    public static function unicodeLetters($value, $message = '')
1027
    {
1028 28
        static::string($value);
1029
1030 28
        if (!\preg_match('/^\p{L}+$/u', $value)) {
1031 16
            static::reportInvalidArgument(\sprintf(
1032 16
                $message ?: 'Expected a value to contain only Unicode letters. Got: %s',
1033 16
                static::valueToString($value)
1034
            ));
1035
        }
1036 12
    }
1037
1038
    /**
1039
     * @param mixed $value
1040
     * @param string $message
1041
     */
1042 12 View Code Duplication
    public static function alpha($value, $message = '')
1043
    {
1044 12
        $locale = \setlocale(LC_CTYPE, 0);
1045 12
        \setlocale(LC_CTYPE, 'C');
1046 12
        $valid = !\ctype_alpha($value);
1047 12
        \setlocale(LC_CTYPE, $locale);
1048
1049 12
        if ($valid) {
1050 8
            static::reportInvalidArgument(\sprintf(
1051 8
                $message ?: 'Expected a value to contain only letters. Got: %s',
1052 8
                static::valueToString($value)
1053
            ));
1054
        }
1055 4
    }
1056
1057
    /**
1058
     * @param mixed $value
1059
     * @param string $message
1060
     */
1061 12 View Code Duplication
    public static function digits($value, $message = '')
1062
    {
1063 12
        $locale = \setlocale(LC_CTYPE, 0);
1064 12
        \setlocale(LC_CTYPE, 'C');
1065 12
        $valid = !\ctype_digit($value);
1066 12
        \setlocale(LC_CTYPE, $locale);
1067
1068 12
        if ($valid) {
1069 8
            static::reportInvalidArgument(\sprintf(
1070 8
                $message ?: 'Expected a value to contain digits only. Got: %s',
1071 8
                static::valueToString($value)
1072
            ));
1073
        }
1074 4
    }
1075
1076
    /**
1077
     * @param mixed $value
1078
     * @param string $message
1079
     */
1080 12 View Code Duplication
    public static function alnum($value, $message = '')
1081
    {
1082 12
        $locale = \setlocale(LC_CTYPE, 0);
1083 12
        \setlocale(LC_CTYPE, 'C');
1084 12
        $valid = !\ctype_alnum($value);
1085 12
        \setlocale(LC_CTYPE, $locale);
1086
1087 12
        if ($valid) {
1088 8
            static::reportInvalidArgument(\sprintf(
1089 8
                $message ?: 'Expected a value to contain letters and digits only. Got: %s',
1090 8
                static::valueToString($value)
1091
            ));
1092
        }
1093 4
    }
1094
1095
    /**
1096
     * @param mixed $value
1097
     * @param string $message
1098
     */
1099 16 View Code Duplication
    public static function lower($value, $message = '')
1100
    {
1101 16
        $locale = \setlocale(LC_CTYPE, 0);
1102 16
        \setlocale(LC_CTYPE, 'C');
1103 16
        $valid = !\ctype_lower($value);
1104 16
        \setlocale(LC_CTYPE, $locale);
1105
1106 16
        if ($valid) {
1107 12
            static::reportInvalidArgument(\sprintf(
1108 12
                $message ?: 'Expected a value to contain lowercase characters only. Got: %s',
1109 12
                static::valueToString($value)
1110
            ));
1111
        }
1112 4
    }
1113
1114
    /**
1115
     * @param mixed $value
1116
     * @param string $message
1117
     */
1118 16 View Code Duplication
    public static function upper($value, $message = '')
1119
    {
1120 16
        $locale = \setlocale(LC_CTYPE, 0);
1121 16
        \setlocale(LC_CTYPE, 'C');
1122 16
        $valid = !\ctype_upper($value);
1123 16
        \setlocale(LC_CTYPE, $locale);
1124
1125 16
        if ($valid) {
1126 12
            static::reportInvalidArgument(\sprintf(
1127 12
                $message ?: 'Expected a value to contain uppercase characters only. Got: %s',
1128 12
                static::valueToString($value)
1129
            ));
1130
        }
1131 4
    }
1132
1133
    /**
1134
     * @param mixed $value
1135
     * @param mixed $length
1136
     * @param string $message
1137
     */
1138 36
    public static function length($value, $length, $message = '')
1139
    {
1140 36
        if ($length !== static::strlen($value)) {
1141 24
            static::reportInvalidArgument(\sprintf(
1142 24
                $message ?: 'Expected a value to contain %2$s characters. Got: %s',
1143 24
                static::valueToString($value),
1144 24
                $length
1145
            ));
1146
        }
1147 12
    }
1148
1149
    /**
1150
     * Inclusive min
1151
     *
1152
     * @param mixed $value
1153
     * @param mixed $min
1154
     * @param string $message
1155
     */
1156 36
    public static function minLength($value, $min, $message = '')
1157
    {
1158 36
        if (static::strlen($value) < $min) {
1159 12
            static::reportInvalidArgument(\sprintf(
1160 12
                $message ?: 'Expected a value to contain at least %2$s characters. Got: %s',
1161 12
                static::valueToString($value),
1162 12
                $min
1163
            ));
1164
        }
1165 24
    }
1166
1167
    /**
1168
     * Inclusive max
1169
     *
1170
     * @param mixed $value
1171
     * @param mixed $max
1172
     * @param string $message
1173
     */
1174 36
    public static function maxLength($value, $max, $message = '')
1175
    {
1176 36
        if (static::strlen($value) > $max) {
1177 12
            static::reportInvalidArgument(\sprintf(
1178 12
                $message ?: 'Expected a value to contain at most %2$s characters. Got: %s',
1179 12
                static::valueToString($value),
1180 12
                $max
1181
            ));
1182
        }
1183 24
    }
1184
1185
    /**
1186
     * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion.
1187
     *
1188
     * @param mixed $value
1189
     * @param mixed $min
1190
     * @param mixed $max
1191
     * @param string $message
1192
     */
1193 60 View Code Duplication
    public static function lengthBetween($value, $min, $max, $message = '')
1194
    {
1195 60
        $length = static::strlen($value);
1196
1197 60
        if ($length < $min || $length > $max) {
1198 24
            static::reportInvalidArgument(\sprintf(
1199 24
                $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s',
1200 24
                static::valueToString($value),
1201 24
                $min,
1202 24
                $max
1203
            ));
1204
        }
1205 36
    }
1206
1207
    /**
1208
     * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file.
1209
     *
1210
     * @param mixed $value
1211
     * @param string $message
1212
     */
1213 36 View Code Duplication
    public static function fileExists($value, $message = '')
1214
    {
1215 36
        static::string($value);
1216
1217 36
        if (!\file_exists($value)) {
1218 12
            static::reportInvalidArgument(\sprintf(
1219 12
                $message ?: 'The file %s does not exist.',
1220 12
                static::valueToString($value)
1221
            ));
1222
        }
1223 24
    }
1224
1225
    /**
1226
     * @param mixed $value
1227
     * @param string $message
1228
     */
1229 12 View Code Duplication
    public static function file($value, $message = '')
1230
    {
1231 12
        static::fileExists($value, $message);
1232
1233 8
        if (!\is_file($value)) {
1234 4
            static::reportInvalidArgument(\sprintf(
1235 4
                $message ?: 'The path %s is not a file.',
1236 4
                static::valueToString($value)
1237
            ));
1238
        }
1239 4
    }
1240
1241
    /**
1242
     * @param mixed $value
1243
     * @param string $message
1244
     */
1245 12 View Code Duplication
    public static function directory($value, $message = '')
1246
    {
1247 12
        static::fileExists($value, $message);
1248
1249 8
        if (!\is_dir($value)) {
1250 4
            static::reportInvalidArgument(\sprintf(
1251 4
                $message ?: 'The path %s is no directory.',
1252 4
                static::valueToString($value)
1253
            ));
1254
        }
1255 4
    }
1256
1257
    /**
1258
     * @param mixed $value
1259
     * @param string $message
1260
     */
1261
    public static function readable($value, $message = '')
1262
    {
1263
        if (!\is_readable($value)) {
1264
            static::reportInvalidArgument(\sprintf(
1265
                $message ?: 'The path %s is not readable.',
1266
                static::valueToString($value)
1267
            ));
1268
        }
1269
    }
1270
1271
    /**
1272
     * @param mixed $value
1273
     * @param string $message
1274
     */
1275
    public static function writable($value, $message = '')
1276
    {
1277
        if (!\is_writable($value)) {
1278
            static::reportInvalidArgument(\sprintf(
1279
                $message ?: 'The path %s is not writable.',
1280
                static::valueToString($value)
1281
            ));
1282
        }
1283
    }
1284
1285
    /**
1286
     * @psalm-assert class-string $value
1287
     *
1288
     * @param mixed $value
1289
     * @param string $message
1290
     */
1291 8
    public static function classExists($value, $message = '')
1292
    {
1293 8
        if (!\class_exists($value)) {
1294 4
            static::reportInvalidArgument(\sprintf(
1295 4
                $message ?: 'Expected an existing class name. Got: %s',
1296 4
                static::valueToString($value)
1297
            ));
1298
        }
1299 4
    }
1300
1301
    /**
1302
     * @param mixed $value
1303
     * @param string|object $class
1304
     * @param string $message
1305
     */
1306 8
    public static function subclassOf($value, $class, $message = '')
1307
    {
1308 8
        if (!\is_subclass_of($value, $class)) {
1309 4
            static::reportInvalidArgument(\sprintf(
1310 4
                $message ?: 'Expected a sub-class of %2$s. Got: %s',
1311 4
                static::valueToString($value),
1312 4
                static::valueToString($class)
1313
            ));
1314
        }
1315 4
    }
1316
1317
    /**
1318
     * @psalm-assert class-string $value
1319
     *
1320
     * @param mixed $value
1321
     * @param string $message
1322
     */
1323 8
    public static function interfaceExists($value, $message = '')
1324
    {
1325 8
        if (!\interface_exists($value)) {
1326 4
            static::reportInvalidArgument(\sprintf(
1327 4
                $message ?: 'Expected an existing interface name. got %s',
1328 4
                static::valueToString($value)
1329
            ));
1330
        }
1331 4
    }
1332
1333
    /**
1334
     * @param mixed $value
1335
     * @param mixed $interface
1336
     * @param string $message
1337
     */
1338 8 View Code Duplication
    public static function implementsInterface($value, $interface, $message = '')
1339
    {
1340 8
        if (!\in_array($interface, \class_implements($value))) {
1341 4
            static::reportInvalidArgument(\sprintf(
1342 4
                $message ?: 'Expected an implementation of %2$s. Got: %s',
1343 4
                static::valueToString($value),
1344 4
                static::valueToString($interface)
1345
            ));
1346
        }
1347 4
    }
1348
1349
    /**
1350
     * @param string|object $classOrObject
1351
     * @param mixed $property
1352
     * @param string $message
1353
     */
1354 12 View Code Duplication
    public static function propertyExists($classOrObject, $property, $message = '')
1355
    {
1356 12
        if (!\property_exists($classOrObject, $property)) {
1357 4
            static::reportInvalidArgument(\sprintf(
1358 4
                $message ?: 'Expected the property %s to exist.',
1359 4
                static::valueToString($property)
1360
            ));
1361
        }
1362 8
    }
1363
1364
    /**
1365
     * @param string|object $classOrObject
1366
     * @param mixed $property
1367
     * @param string $message
1368
     */
1369 12 View Code Duplication
    public static function propertyNotExists($classOrObject, $property, $message = '')
1370
    {
1371 12
        if (\property_exists($classOrObject, $property)) {
1372 8
            static::reportInvalidArgument(\sprintf(
1373 8
                $message ?: 'Expected the property %s to not exist.',
1374 8
                static::valueToString($property)
1375
            ));
1376
        }
1377 4
    }
1378
1379
    /**
1380
     * @param string|object $classOrObject
1381
     * @param mixed $method
1382
     * @param string $message
1383
     */
1384 27 View Code Duplication
    public static function methodExists($classOrObject, $method, $message = '')
1385
    {
1386 27
        if (!\method_exists($classOrObject, $method)) {
1387 19
            static::reportInvalidArgument(\sprintf(
1388 19
                $message ?: 'Expected the method %s to exist.',
1389 19
                static::valueToString($method)
1390
            ));
1391
        }
1392 8
    }
1393
1394
    /**
1395
     * @param string|object $classOrObject
1396
     * @param mixed $method
1397
     * @param string $message
1398
     */
1399 27 View Code Duplication
    public static function methodNotExists($classOrObject, $method, $message = '')
1400
    {
1401 27
        if (\method_exists($classOrObject, $method)) {
1402 8
            static::reportInvalidArgument(\sprintf(
1403 8
                $message ?: 'Expected the method %s to not exist.',
1404 8
                static::valueToString($method)
1405
            ));
1406
        }
1407 19
    }
1408
1409
    /**
1410
     * @param array $array
1411
     * @param string|int $key
1412
     * @param string $message
1413
     */
1414 12 View Code Duplication
    public static function keyExists($array, $key, $message = '')
1415
    {
1416 12
        if (!(isset($array[$key]) || \array_key_exists($key, $array))) {
1417 4
            static::reportInvalidArgument(\sprintf(
1418 4
                $message ?: 'Expected the key %s to exist.',
1419 4
                static::valueToString($key)
1420
            ));
1421
        }
1422 8
    }
1423
1424
    /**
1425
     * @param array $array
1426
     * @param string|int $key
1427
     * @param string $message
1428
     */
1429 12 View Code Duplication
    public static function keyNotExists($array, $key, $message = '')
1430
    {
1431 12
        if (isset($array[$key]) || \array_key_exists($key, $array)) {
1432 8
            static::reportInvalidArgument(\sprintf(
1433 8
                $message ?: 'Expected the key %s to not exist.',
1434 8
                static::valueToString($key)
1435
            ));
1436
        }
1437 4
    }
1438
1439
    /**
1440
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2
1441
     *
1442
     * @param mixed $array
1443
     * @param mixed $number
1444
     * @param string $message
1445
     */
1446 8
    public static function count($array, $number, $message = '')
1447
    {
1448 8
        static::eq(
1449 8
            \count($array),
1450
            $number,
1451 8
            $message ?: \sprintf('Expected an array to contain %d elements. Got: %d.', $number, \count($array))
1452
        );
1453 4
    }
1454
1455
    /**
1456
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2
1457
     *
1458
     * @param mixed $array
1459
     * @param mixed $min
1460
     * @param string $message
1461
     */
1462 12 View Code Duplication
    public static function minCount($array, $min, $message = '')
1463
    {
1464 12
        if (\count($array) < $min) {
1465 4
            static::reportInvalidArgument(\sprintf(
1466 4
                $message ?: 'Expected an array to contain at least %2$d elements. Got: %d',
1467 4
                \count($array),
1468 4
                $min
1469
            ));
1470
        }
1471 8
    }
1472
1473
    /**
1474
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2
1475
     *
1476
     * @param mixed $array
1477
     * @param mixed $max
1478
     * @param string $message
1479
     */
1480 12 View Code Duplication
    public static function maxCount($array, $max, $message = '')
1481
    {
1482 12
        if (\count($array) > $max) {
1483 4
            static::reportInvalidArgument(\sprintf(
1484 4
                $message ?: 'Expected an array to contain at most %2$d elements. Got: %d',
1485 4
                \count($array),
1486 4
                $max
1487
            ));
1488
        }
1489 8
    }
1490
1491
    /**
1492
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2
1493
     *
1494
     * @param mixed $array
1495
     * @param mixed $min
1496
     * @param mixed $max
1497
     * @param string $message
1498
     */
1499 20
    public static function countBetween($array, $min, $max, $message = '')
1500
    {
1501 20
        $count = \count($array);
1502
1503 20
        if ($count < $min || $count > $max) {
1504 8
            static::reportInvalidArgument(\sprintf(
1505 8
                $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d',
1506 8
                $count,
1507 8
                $min,
1508 8
                $max
1509
            ));
1510
        }
1511 12
    }
1512
1513
    /**
1514
     * @param mixed $array
1515
     * @param string $message
1516
     */
1517 24
    public static function isList($array, $message = '')
1518
    {
1519 24
        if (!\is_array($array) || !$array || \array_keys($array) !== \range(0, \count($array) - 1)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1520 20
            static::reportInvalidArgument(
1521 20
                $message ?: 'Expected list - non-associative array.'
1522
            );
1523
        }
1524 4
    }
1525
1526
    /**
1527
     * @param mixed $array
1528
     * @param string $message
1529
     */
1530 16
    public static function isMap($array, $message = '')
1531
    {
1532
        if (
1533 16
            !\is_array($array) ||
1534 16
            !$array ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1535
            \array_keys($array) !== \array_filter(\array_keys($array), function ($key) {
1536 12
                return \is_string($key);
1537 16
            })
1538
        ) {
1539 12
            static::reportInvalidArgument(
1540 12
                $message ?: 'Expected map - associative array with string keys.'
1541
            );
1542
        }
1543 4
    }
1544
1545
    /**
1546
     * @param mixed $value
1547
     * @param string $message
1548
     */
1549 56
    public static function uuid($value, $message = '')
1550
    {
1551 56
        $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value);
1552
1553
        // The nil UUID is special form of UUID that is specified to have all
1554
        // 128 bits set to zero.
1555 56
        if ('00000000-0000-0000-0000-000000000000' === $value) {
1556 4
            return;
1557
        }
1558
1559 52
        if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) {
1560 20
            static::reportInvalidArgument(\sprintf(
1561 20
                $message ?: 'Value %s is not a valid UUID.',
1562 20
                static::valueToString($value)
1563
            ));
1564
        }
1565 32
    }
1566
1567
    /**
1568
     * @param Closure $expression
1569
     * @param string|object $class
1570
     * @param string $message
1571
     */
1572 24
    public static function throws(Closure $expression, $class = 'Exception', $message = '')
1573
    {
1574 24
        static::string($class);
1575
1576 24
        $actual = 'none';
1577
1578
        try {
1579 24
            $expression();
1580 24
        } catch (Exception $e) {
1581 20
            $actual = \get_class($e);
1582 20
            if ($e instanceof $class) {
1583 20
                return;
1584
            }
1585 4
        } catch (Throwable $e) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
1586 4
            $actual = \get_class($e);
1587 4
            if ($e instanceof $class) {
1588 4
                return;
1589
            }
1590
        }
1591
1592 8
        static::reportInvalidArgument($message ?: \sprintf(
1593 8
            'Expected to throw "%s", got "%s"',
1594 8
            $class,
1595 8
            $actual
1596
        ));
1597
    }
1598
1599 1383
    public static function __callStatic($name, $arguments)
1600
    {
1601 1383
        if ('nullOr' === \substr($name, 0, 6)) {
1602 514
            if (null !== $arguments[0]) {
1603 421
                $method = \lcfirst(\substr($name, 6));
1604 421
                \call_user_func_array(array('static', $method), $arguments);
1605
            }
1606
1607 296
            return;
1608
        }
1609
1610 869
        if ('all' === \substr($name, 0, 3)) {
1611 868
            static::isIterable($arguments[0]);
1612
1613 868
            $method = \lcfirst(\substr($name, 3));
1614 868
            $args = $arguments;
1615
1616 868
            foreach ($arguments[0] as $entry) {
1617 868
                $args[0] = $entry;
1618
1619 868
                \call_user_func_array(array('static', $method), $args);
1620
            }
1621
1622 412
            return;
1623
        }
1624
1625 1
        throw new BadMethodCallException('No such method: '.$name);
1626
    }
1627
1628
    /**
1629
     * @param mixed $value
1630
     *
1631
     * @return string
1632
     */
1633 694
    protected static function valueToString($value)
1634
    {
1635 694
        if (null === $value) {
1636 20
            return 'null';
1637
        }
1638
1639 676
        if (true === $value) {
1640 15
            return 'true';
1641
        }
1642
1643 666
        if (false === $value) {
1644 25
            return 'false';
1645
        }
1646
1647 641
        if (\is_array($value)) {
1648 13
            return 'array';
1649
        }
1650
1651 628
        if (\is_object($value)) {
1652 2
            if (\method_exists($value, '__toString')) {
1653 1
                return \get_class($value).': '.self::valueToString($value->__toString());
1654
            }
1655
1656 1
            return \get_class($value);
1657
        }
1658
1659 627
        if (\is_resource($value)) {
1660 1
            return 'resource';
1661
        }
1662
1663 627
        if (\is_string($value)) {
1664 525
            return '"'.$value.'"';
1665
        }
1666
1667 110
        return (string) $value;
1668
    }
1669
1670
    /**
1671
     * @param mixed $value
1672
     *
1673
     * @return string
1674
     */
1675 169
    protected static function typeToString($value)
1676
    {
1677 169
        return \is_object($value) ? \get_class($value) : \gettype($value);
1678
    }
1679
1680 168
    protected static function strlen($value)
1681
    {
1682 168
        if (!\function_exists('mb_detect_encoding')) {
1683
            return \strlen($value);
1684
        }
1685
1686 168
        if (false === $encoding = \mb_detect_encoding($value)) {
1687
            return \strlen($value);
1688
        }
1689
1690 168
        return \mb_strlen($value, $encoding);
1691
    }
1692
1693
    /**
1694
     * @param string $message
1695
     */
1696 918
    protected static function reportInvalidArgument($message)
1697
    {
1698 918
        throw new InvalidArgumentException($message);
1699
    }
1700
1701
    private function __construct()
1702
    {
1703
    }
1704
}
1705