Failed Conditions
Push — master ( bb3cf2...1838a0 )
by Tobias
48:55 queued 47:43
created

src/Assert.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 DateTime;
19
use DateTimeImmutable;
20
use Exception;
21
use InvalidArgumentException;
22
use ResourceBundle;
23
use SimpleXMLElement;
24
use Throwable;
25
use Traversable;
26
27
/**
28
 * Efficient assertions to validate the input/output of your methods.
29
 *
30
 * @mixin Mixin
31
 *
32
 * @since  1.0
33
 *
34
 * @author Bernhard Schussek <[email protected]>
35
 */
36
class Assert
37
{
38
    /**
39
     * @psalm-pure
40
     * @psalm-assert string $value
41
     *
42
     * @param mixed  $value
43
     * @param string $message
44
     *
45
     * @throws InvalidArgumentException
46
     */
47 241
    public static function string($value, $message = '')
48
    {
49 241
        if (!\is_string($value)) {
50 45
            static::reportInvalidArgument(\sprintf(
51 45
                $message ?: 'Expected a string. Got: %s',
52 45
                static::typeToString($value)
53
            ));
54
        }
55 196
    }
56
57
    /**
58
     * @psalm-pure
59
     * @psalm-assert non-empty-string $value
60
     *
61
     * @param mixed  $value
62
     * @param string $message
63
     *
64
     * @throws InvalidArgumentException
65
     */
66 16
    public static function stringNotEmpty($value, $message = '')
67
    {
68 16
        static::string($value, $message);
69 12
        static::notEq($value, '', $message);
70 8
    }
71
72
    /**
73
     * @psalm-pure
74
     * @psalm-assert int $value
75
     *
76
     * @param mixed  $value
77
     * @param string $message
78
     *
79
     * @throws InvalidArgumentException
80
     */
81 17
    public static function integer($value, $message = '')
82
    {
83 17
        if (!\is_int($value)) {
84 13
            static::reportInvalidArgument(\sprintf(
85 13
                $message ?: 'Expected an integer. Got: %s',
86 13
                static::typeToString($value)
87
            ));
88
        }
89 4
    }
90
91
    /**
92
     * @psalm-pure
93
     * @psalm-assert numeric $value
94
     *
95
     * @param mixed  $value
96
     * @param string $message
97
     *
98
     * @throws InvalidArgumentException
99
     */
100 16
    public static function integerish($value, $message = '')
101
    {
102 16
        if (!\is_numeric($value) || $value != (int) $value) {
103 4
            static::reportInvalidArgument(\sprintf(
104 4
                $message ?: 'Expected an integerish value. Got: %s',
105 4
                static::typeToString($value)
106
            ));
107
        }
108 12
    }
109
110
    /**
111
     * @psalm-pure
112
     * @psalm-assert float $value
113
     *
114
     * @param mixed  $value
115
     * @param string $message
116
     *
117
     * @throws InvalidArgumentException
118
     */
119 16
    public static function float($value, $message = '')
120
    {
121 16
        if (!\is_float($value)) {
122 8
            static::reportInvalidArgument(\sprintf(
123 8
                $message ?: 'Expected a float. Got: %s',
124 8
                static::typeToString($value)
125
            ));
126
        }
127 8
    }
128
129
    /**
130
     * @psalm-pure
131
     * @psalm-assert numeric $value
132
     *
133
     * @param mixed  $value
134
     * @param string $message
135
     *
136
     * @throws InvalidArgumentException
137
     */
138 20
    public static function numeric($value, $message = '')
139
    {
140 20
        if (!\is_numeric($value)) {
141 4
            static::reportInvalidArgument(\sprintf(
142 4
                $message ?: 'Expected a numeric. Got: %s',
143 4
                static::typeToString($value)
144
            ));
145
        }
146 16
    }
147
148
    /**
149
     * @psalm-pure
150
     * @psalm-assert int $value
151
     *
152
     * @param mixed  $value
153
     * @param string $message
154
     *
155
     * @throws InvalidArgumentException
156
     */
157 24
    public static function natural($value, $message = '')
158
    {
159 24
        if (!\is_int($value) || $value < 0) {
160 16
            static::reportInvalidArgument(\sprintf(
161 16
                $message ?: 'Expected a non-negative integer. Got: %s',
162 16
                static::valueToString($value)
163
            ));
164
        }
165 8
    }
166
167
    /**
168
     * @psalm-pure
169
     * @psalm-assert bool $value
170
     *
171
     * @param mixed  $value
172
     * @param string $message
173
     *
174
     * @throws InvalidArgumentException
175
     */
176 16
    public static function boolean($value, $message = '')
177
    {
178 16
        if (!\is_bool($value)) {
179 8
            static::reportInvalidArgument(\sprintf(
180 8
                $message ?: 'Expected a boolean. Got: %s',
181 8
                static::typeToString($value)
182
            ));
183
        }
184 8
    }
185
186
    /**
187
     * @psalm-pure
188
     * @psalm-assert scalar $value
189
     *
190
     * @param mixed  $value
191
     * @param string $message
192
     *
193
     * @throws InvalidArgumentException
194
     */
195 23
    public static function scalar($value, $message = '')
196
    {
197 23
        if (!\is_scalar($value)) {
198 11
            static::reportInvalidArgument(\sprintf(
199 11
                $message ?: 'Expected a scalar. Got: %s',
200 11
                static::typeToString($value)
201
            ));
202
        }
203 12
    }
204
205
    /**
206
     * @psalm-pure
207
     * @psalm-assert object $value
208
     *
209
     * @param mixed  $value
210
     * @param string $message
211
     *
212
     * @throws InvalidArgumentException
213
     */
214 23
    public static function object($value, $message = '')
215
    {
216 23
        if (!\is_object($value)) {
217 15
            static::reportInvalidArgument(\sprintf(
218 15
                $message ?: 'Expected an object. Got: %s',
219 15
                static::typeToString($value)
220
            ));
221
        }
222 8
    }
223
224
    /**
225
     * @psalm-pure
226
     * @psalm-assert resource $value
227
     *
228
     * @param mixed       $value
229
     * @param string|null $type    type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
230
     * @param string      $message
231
     *
232
     * @throws InvalidArgumentException
233
     */
234 16
    public static function resource($value, $type = null, $message = '')
235
    {
236 16
        if (!\is_resource($value)) {
237 4
            static::reportInvalidArgument(\sprintf(
238 4
                $message ?: 'Expected a resource. Got: %s',
239 4
                static::typeToString($value)
240
            ));
241
        }
242
243 12
        if ($type && $type !== \get_resource_type($value)) {
244 4
            static::reportInvalidArgument(\sprintf(
245 4
                $message ?: 'Expected a resource of type %2$s. Got: %s',
246 4
                static::typeToString($value),
247 4
                $type
248
            ));
249
        }
250 8
    }
251
252
    /**
253
     * @psalm-pure
254
     * @psalm-assert callable $value
255
     *
256
     * @param mixed  $value
257
     * @param string $message
258
     *
259
     * @throws InvalidArgumentException
260
     */
261 20
    public static function isCallable($value, $message = '')
262
    {
263 20
        if (!\is_callable($value)) {
264 8
            static::reportInvalidArgument(\sprintf(
265 8
                $message ?: 'Expected a callable. Got: %s',
266 8
                static::typeToString($value)
267
            ));
268
        }
269 12
    }
270
271
    /**
272
     * @psalm-pure
273
     * @psalm-assert array $value
274
     *
275
     * @param mixed  $value
276
     * @param string $message
277
     *
278
     * @throws InvalidArgumentException
279
     */
280 20
    public static function isArray($value, $message = '')
281
    {
282 20
        if (!\is_array($value)) {
283 12
            static::reportInvalidArgument(\sprintf(
284 12
                $message ?: 'Expected an array. Got: %s',
285 12
                static::typeToString($value)
286
            ));
287
        }
288 8
    }
289
290
    /**
291
     * @psalm-pure
292
     * @psalm-assert iterable $value
293
     *
294
     * @deprecated use "isIterable" or "isInstanceOf" instead
295
     *
296
     * @param mixed  $value
297
     * @param string $message
298
     *
299
     * @throws InvalidArgumentException
300
     */
301 20
    public static function isTraversable($value, $message = '')
302
    {
303 20
        @\trigger_error(
304 20
            \sprintf(
305
                '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.',
306 20
                __METHOD__
307
            ),
308 20
            \E_USER_DEPRECATED
309
        );
310
311 20
        if (!\is_array($value) && !($value instanceof Traversable)) {
312 8
            static::reportInvalidArgument(\sprintf(
313 8
                $message ?: 'Expected a traversable. Got: %s',
314 8
                static::typeToString($value)
315
            ));
316
        }
317 12
    }
318
319
    /**
320
     * @psalm-pure
321
     * @psalm-assert array|ArrayAccess $value
322
     *
323
     * @param mixed  $value
324
     * @param string $message
325
     *
326
     * @throws InvalidArgumentException
327
     */
328 20 View Code Duplication
    public static function isArrayAccessible($value, $message = '')
329
    {
330 20
        if (!\is_array($value) && !($value instanceof ArrayAccess)) {
331 8
            static::reportInvalidArgument(\sprintf(
332 8
                $message ?: 'Expected an array accessible. Got: %s',
333 8
                static::typeToString($value)
334
            ));
335
        }
336 12
    }
337
338
    /**
339
     * @psalm-pure
340
     * @psalm-assert countable $value
341
     *
342
     * @param mixed  $value
343
     * @param string $message
344
     *
345
     * @throws InvalidArgumentException
346
     */
347 28
    public static function isCountable($value, $message = '')
348
    {
349
        if (
350 28
            !\is_array($value)
351 28
            && !($value instanceof Countable)
352 28
            && !($value instanceof ResourceBundle)
353 28
            && !($value instanceof SimpleXMLElement)
354
        ) {
355 12
            static::reportInvalidArgument(\sprintf(
356 12
                $message ?: 'Expected a countable. Got: %s',
357 12
                static::typeToString($value)
358
            ));
359
        }
360 16
    }
361
362
    /**
363
     * @psalm-pure
364
     * @psalm-assert iterable $value
365
     *
366
     * @param mixed  $value
367
     * @param string $message
368
     *
369
     * @throws InvalidArgumentException
370
     */
371 1044 View Code Duplication
    public static function isIterable($value, $message = '')
372
    {
373 1044
        if (!\is_array($value) && !($value instanceof Traversable)) {
374 8
            static::reportInvalidArgument(\sprintf(
375 8
                $message ?: 'Expected an iterable. Got: %s',
376 8
                static::typeToString($value)
377
            ));
378
        }
379 1040
    }
380
381
    /**
382
     * @psalm-pure
383
     * @psalm-template ExpectedType of object
384
     * @psalm-param class-string<ExpectedType> $class
385
     * @psalm-assert ExpectedType $value
386
     *
387
     * @param mixed         $value
388
     * @param string|object $class
389
     * @param string        $message
390
     *
391
     * @throws InvalidArgumentException
392
     */
393 19
    public static function isInstanceOf($value, $class, $message = '')
394
    {
395 19
        if (!($value instanceof $class)) {
396 15
            static::reportInvalidArgument(\sprintf(
397 15
                $message ?: 'Expected an instance of %2$s. Got: %s',
398 15
                static::typeToString($value),
399 15
                $class
400
            ));
401
        }
402 4
    }
403
404
    /**
405
     * @psalm-pure
406
     * @psalm-template ExpectedType of object
407
     * @psalm-param class-string<ExpectedType> $class
408
     * @psalm-assert !ExpectedType $value
409
     *
410
     * @param mixed         $value
411
     * @param string|object $class
412
     * @param string        $message
413
     *
414
     * @throws InvalidArgumentException
415
     */
416 16
    public static function notInstanceOf($value, $class, $message = '')
417
    {
418 16
        if ($value instanceof $class) {
419 4
            static::reportInvalidArgument(\sprintf(
420 4
                $message ?: 'Expected an instance other than %2$s. Got: %s',
421 4
                static::typeToString($value),
422 4
                $class
423
            ));
424
        }
425 12
    }
426
427
    /**
428
     * @psalm-pure
429
     * @psalm-param array<class-string> $classes
430
     *
431
     * @param mixed                $value
432
     * @param array<object|string> $classes
433
     * @param string               $message
434
     *
435
     * @throws InvalidArgumentException
436
     */
437 20
    public static function isInstanceOfAny($value, array $classes, $message = '')
438
    {
439 20
        foreach ($classes as $class) {
440 20
            if ($value instanceof $class) {
441 8
                return;
442
            }
443
        }
444
445 12
        static::reportInvalidArgument(\sprintf(
446 12
            $message ?: 'Expected an instance of any of %2$s. Got: %s',
447 12
            static::typeToString($value),
448 12
            \implode(', ', \array_map(array('static', 'valueToString'), $classes))
449
        ));
450
    }
451
452
    /**
453
     * @psalm-pure
454
     * @psalm-template ExpectedType of object
455
     * @psalm-param class-string<ExpectedType> $class
456
     * @psalm-assert ExpectedType|class-string<ExpectedType> $value
457
     *
458
     * @param object|string $value
459
     * @param string        $class
460
     * @param string        $message
461
     *
462
     * @throws InvalidArgumentException
463
     */
464 20 View Code Duplication
    public static function isAOf($value, $class, $message = '')
465
    {
466 20
        static::string($class, 'Expected class as a string. Got: %s');
467
468 16
        if (!\is_a($value, $class, \is_string($value))) {
469 12
            static::reportInvalidArgument(sprintf(
470 12
                $message ?: 'Expected an instance of this class or to this class among his parents %2$s. Got: %s',
471 12
                static::typeToString($value),
472
                $class
473
            ));
474
        }
475 4
    }
476
477
    /**
478
     * @psalm-pure
479
     * @psalm-template UnexpectedType of object
480
     * @psalm-param class-string<UnexpectedType> $class
481
     * @psalm-assert !UnexpectedType $value
482
     * @psalm-assert !class-string<UnexpectedType> $value
483
     *
484
     * @param object|string $value
485
     * @param string        $class
486
     * @param string        $message
487
     *
488
     * @throws InvalidArgumentException
489
     */
490 20 View Code Duplication
    public static function isNotA($value, $class, $message = '')
491
    {
492 20
        static::string($class, 'Expected class as a string. Got: %s');
493
494 16
        if (\is_a($value, $class, \is_string($value))) {
495 4
            static::reportInvalidArgument(sprintf(
496 4
                $message ?: 'Expected an instance of this class or to this class among his parents other than %2$s. Got: %s',
497 4
                static::typeToString($value),
498
                $class
499
            ));
500
        }
501 12
    }
502
503
    /**
504
     * @psalm-pure
505
     * @psalm-param array<class-string> $classes
506
     *
507
     * @param object|string $value
508
     * @param string[]      $classes
509
     * @param string        $message
510
     *
511
     * @throws InvalidArgumentException
512
     */
513 24
    public static function isAnyOf($value, array $classes, $message = '')
514
    {
515 24
        foreach ($classes as $class) {
516 24
            static::string($class, 'Expected class as a string. Got: %s');
517
518 20
            if (\is_a($value, $class, \is_string($value))) {
519 8
                return;
520
            }
521
        }
522
523 12
        static::reportInvalidArgument(sprintf(
524 12
            $message ?: 'Expected an any of instance of this class or to this class among his parents other than %2$s. Got: %s',
525 12
            static::typeToString($value),
526 12
            \implode(', ', \array_map(array('static', 'valueToString'), $classes))
527
        ));
528
    }
529
530
    /**
531
     * @psalm-pure
532
     * @psalm-assert empty $value
533
     *
534
     * @param mixed  $value
535
     * @param string $message
536
     *
537
     * @throws InvalidArgumentException
538
     */
539 23
    public static function isEmpty($value, $message = '')
540
    {
541 23
        if (!empty($value)) {
542 8
            static::reportInvalidArgument(\sprintf(
543 8
                $message ?: 'Expected an empty value. Got: %s',
544 8
                static::valueToString($value)
545
            ));
546
        }
547 15
    }
548
549
    /**
550
     * @psalm-pure
551
     * @psalm-assert !empty $value
552
     *
553
     * @param mixed  $value
554
     * @param string $message
555
     *
556
     * @throws InvalidArgumentException
557
     */
558 55
    public static function notEmpty($value, $message = '')
559
    {
560 55
        if (empty($value)) {
561 23
            static::reportInvalidArgument(\sprintf(
562 23
                $message ?: 'Expected a non-empty value. Got: %s',
563 23
                static::valueToString($value)
564
            ));
565
        }
566 32
    }
567
568
    /**
569
     * @psalm-pure
570
     * @psalm-assert null $value
571
     *
572
     * @param mixed  $value
573
     * @param string $message
574
     *
575
     * @throws InvalidArgumentException
576
     */
577 11
    public static function null($value, $message = '')
578
    {
579 11
        if (null !== $value) {
580 8
            static::reportInvalidArgument(\sprintf(
581 8
                $message ?: 'Expected null. Got: %s',
582 8
                static::valueToString($value)
583
            ));
584
        }
585 3
    }
586
587
    /**
588
     * @psalm-pure
589
     * @psalm-assert !null $value
590
     *
591
     * @param mixed  $value
592
     * @param string $message
593
     *
594
     * @throws InvalidArgumentException
595
     */
596 11
    public static function notNull($value, $message = '')
597
    {
598 11
        if (null === $value) {
599 3
            static::reportInvalidArgument(
600 3
                $message ?: 'Expected a value other than null.'
601
            );
602
        }
603 8
    }
604
605
    /**
606
     * @psalm-pure
607
     * @psalm-assert true $value
608
     *
609
     * @param mixed  $value
610
     * @param string $message
611
     *
612
     * @throws InvalidArgumentException
613
     */
614 15
    public static function true($value, $message = '')
615
    {
616 15
        if (true !== $value) {
617 11
            static::reportInvalidArgument(\sprintf(
618 11
                $message ?: 'Expected a value to be true. Got: %s',
619 11
                static::valueToString($value)
620
            ));
621
        }
622 4
    }
623
624
    /**
625
     * @psalm-pure
626
     * @psalm-assert false $value
627
     *
628
     * @param mixed  $value
629
     * @param string $message
630
     *
631
     * @throws InvalidArgumentException
632
     */
633 19
    public static function false($value, $message = '')
634
    {
635 19
        if (false !== $value) {
636 15
            static::reportInvalidArgument(\sprintf(
637 15
                $message ?: 'Expected a value to be false. Got: %s',
638 15
                static::valueToString($value)
639
            ));
640
        }
641 4
    }
642
643
    /**
644
     * @psalm-pure
645
     * @psalm-assert !false $value
646
     *
647
     * @param mixed  $value
648
     * @param string $message
649
     *
650
     * @throws InvalidArgumentException
651
     */
652 19
    public static function notFalse($value, $message = '')
653
    {
654 19
        if (false === $value) {
655 4
            static::reportInvalidArgument(
656 4
                $message ?: 'Expected a value other than false.'
657
            );
658
        }
659 15
    }
660
661
    /**
662
     * @param mixed  $value
663
     * @param string $message
664
     *
665
     * @throws InvalidArgumentException
666
     */
667 51 View Code Duplication
    public static function ip($value, $message = '')
668
    {
669 51
        if (false === \filter_var($value, \FILTER_VALIDATE_IP)) {
670 19
            static::reportInvalidArgument(\sprintf(
671 19
                $message ?: 'Expected a value to be an IP. Got: %s',
672 19
                static::valueToString($value)
673
            ));
674
        }
675 32
    }
676
677
    /**
678
     * @param mixed  $value
679
     * @param string $message
680
     *
681
     * @throws InvalidArgumentException
682
     */
683 51 View Code Duplication
    public static function ipv4($value, $message = '')
684
    {
685 51
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
686 35
            static::reportInvalidArgument(\sprintf(
687 35
                $message ?: 'Expected a value to be an IPv4. Got: %s',
688 35
                static::valueToString($value)
689
            ));
690
        }
691 16
    }
692
693
    /**
694
     * @param mixed  $value
695
     * @param string $message
696
     *
697
     * @throws InvalidArgumentException
698
     */
699 51 View Code Duplication
    public static function ipv6($value, $message = '')
700
    {
701 51
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
702 31
            static::reportInvalidArgument(\sprintf(
703 31
                $message ?: 'Expected a value to be an IPv6. Got: %s',
704 31
                static::valueToString($value)
705
            ));
706
        }
707 20
    }
708
709
    /**
710
     * @param mixed  $value
711
     * @param string $message
712
     *
713
     * @throws InvalidArgumentException
714
     */
715 20 View Code Duplication
    public static function email($value, $message = '')
716
    {
717 20
        if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) {
718 12
            static::reportInvalidArgument(\sprintf(
719 12
                $message ?: 'Expected a value to be a valid e-mail address. Got: %s',
720 12
                static::valueToString($value)
721
            ));
722
        }
723 8
    }
724
725
    /**
726
     * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion.
727
     *
728
     * @param array  $values
729
     * @param string $message
730
     *
731
     * @throws InvalidArgumentException
732
     */
733 12
    public static function uniqueValues(array $values, $message = '')
734
    {
735 12
        $allValues = \count($values);
736 12
        $uniqueValues = \count(\array_unique($values));
737
738 12
        if ($allValues !== $uniqueValues) {
739 8
            $difference = $allValues - $uniqueValues;
740
741 8
            static::reportInvalidArgument(\sprintf(
742 8
                $message ?: 'Expected an array of unique values, but %s of them %s duplicated',
743 8
                $difference,
744 8
                (1 === $difference ? 'is' : 'are')
745
            ));
746
        }
747 4
    }
748
749
    /**
750
     * @param mixed  $value
751
     * @param mixed  $expect
752
     * @param string $message
753
     *
754
     * @throws InvalidArgumentException
755
     */
756 33
    public static function eq($value, $expect, $message = '')
757
    {
758 33
        if ($expect != $value) {
759 17
            static::reportInvalidArgument(\sprintf(
760 17
                $message ?: 'Expected a value equal to %2$s. Got: %s',
761 17
                static::valueToString($value),
762 17
                static::valueToString($expect)
763
            ));
764
        }
765 16
    }
766
767
    /**
768
     * @param mixed  $value
769
     * @param mixed  $expect
770
     * @param string $message
771
     *
772
     * @throws InvalidArgumentException
773
     */
774 28
    public static function notEq($value, $expect, $message = '')
775
    {
776 28
        if ($expect == $value) {
777 16
            static::reportInvalidArgument(\sprintf(
778 16
                $message ?: 'Expected a different value than %s.',
779 16
                static::valueToString($expect)
780
            ));
781
        }
782 12
    }
783
784
    /**
785
     * @psalm-pure
786
     *
787
     * @param mixed  $value
788
     * @param mixed  $expect
789
     * @param string $message
790
     *
791
     * @throws InvalidArgumentException
792
     */
793 16
    public static function same($value, $expect, $message = '')
794
    {
795 16
        if ($expect !== $value) {
796 12
            static::reportInvalidArgument(\sprintf(
797 12
                $message ?: 'Expected a value identical to %2$s. Got: %s',
798 12
                static::valueToString($value),
799 12
                static::valueToString($expect)
800
            ));
801
        }
802 4
    }
803
804
    /**
805
     * @psalm-pure
806
     *
807
     * @param mixed  $value
808
     * @param mixed  $expect
809
     * @param string $message
810
     *
811
     * @throws InvalidArgumentException
812
     */
813 16
    public static function notSame($value, $expect, $message = '')
814
    {
815 16
        if ($expect === $value) {
816 4
            static::reportInvalidArgument(\sprintf(
817 4
                $message ?: 'Expected a value not identical to %s.',
818 4
                static::valueToString($expect)
819
            ));
820
        }
821 12
    }
822
823
    /**
824
     * @psalm-pure
825
     *
826
     * @param mixed  $value
827
     * @param mixed  $limit
828
     * @param string $message
829
     *
830
     * @throws InvalidArgumentException
831
     */
832 8
    public static function greaterThan($value, $limit, $message = '')
833
    {
834 8
        if ($value <= $limit) {
835 4
            static::reportInvalidArgument(\sprintf(
836 4
                $message ?: 'Expected a value greater than %2$s. Got: %s',
837 4
                static::valueToString($value),
838 4
                static::valueToString($limit)
839
            ));
840
        }
841 4
    }
842
843
    /**
844
     * @psalm-pure
845
     *
846
     * @param mixed  $value
847
     * @param mixed  $limit
848
     * @param string $message
849
     *
850
     * @throws InvalidArgumentException
851
     */
852 12
    public static function greaterThanEq($value, $limit, $message = '')
853
    {
854 12
        if ($value < $limit) {
855 4
            static::reportInvalidArgument(\sprintf(
856 4
                $message ?: 'Expected a value greater than or equal to %2$s. Got: %s',
857 4
                static::valueToString($value),
858 4
                static::valueToString($limit)
859
            ));
860
        }
861 8
    }
862
863
    /**
864
     * @psalm-pure
865
     *
866
     * @param mixed  $value
867
     * @param mixed  $limit
868
     * @param string $message
869
     *
870
     * @throws InvalidArgumentException
871
     */
872 9
    public static function lessThan($value, $limit, $message = '')
873
    {
874 9
        if ($value >= $limit) {
875 5
            static::reportInvalidArgument(\sprintf(
876 5
                $message ?: 'Expected a value less than %2$s. Got: %s',
877 5
                static::valueToString($value),
878 5
                static::valueToString($limit)
879
            ));
880
        }
881 4
    }
882
883
    /**
884
     * @psalm-pure
885
     *
886
     * @param mixed  $value
887
     * @param mixed  $limit
888
     * @param string $message
889
     *
890
     * @throws InvalidArgumentException
891
     */
892 12
    public static function lessThanEq($value, $limit, $message = '')
893
    {
894 12
        if ($value > $limit) {
895 4
            static::reportInvalidArgument(\sprintf(
896 4
                $message ?: 'Expected a value less than or equal to %2$s. Got: %s',
897 4
                static::valueToString($value),
898 4
                static::valueToString($limit)
899
            ));
900
        }
901 8
    }
902
903
    /**
904
     * Inclusive range, so Assert::(3, 3, 5) passes.
905
     *
906
     * @psalm-pure
907
     *
908
     * @param mixed  $value
909
     * @param mixed  $min
910
     * @param mixed  $max
911
     * @param string $message
912
     *
913
     * @throws InvalidArgumentException
914
     */
915 16 View Code Duplication
    public static function range($value, $min, $max, $message = '')
916
    {
917 16
        if ($value < $min || $value > $max) {
918 8
            static::reportInvalidArgument(\sprintf(
919 8
                $message ?: 'Expected a value between %2$s and %3$s. Got: %s',
920 8
                static::valueToString($value),
921 8
                static::valueToString($min),
922 8
                static::valueToString($max)
923
            ));
924
        }
925 8
    }
926
927
    /**
928
     * A more human-readable alias of Assert::inArray().
929
     *
930
     * @psalm-pure
931
     *
932
     * @param mixed  $value
933
     * @param array  $values
934
     * @param string $message
935
     *
936
     * @throws InvalidArgumentException
937
     */
938 8
    public static function oneOf($value, array $values, $message = '')
939
    {
940 8
        static::inArray($value, $values, $message);
941 4
    }
942
943
    /**
944
     * Does strict comparison, so Assert::inArray(3, ['3']) does not pass the assertion.
945
     *
946
     * @psalm-pure
947
     *
948
     * @param mixed  $value
949
     * @param array  $values
950
     * @param string $message
951
     *
952
     * @throws InvalidArgumentException
953
     */
954 16
    public static function inArray($value, array $values, $message = '')
955
    {
956 16
        if (!\in_array($value, $values, true)) {
957 8
            static::reportInvalidArgument(\sprintf(
958 8
                $message ?: 'Expected one of: %2$s. Got: %s',
959 8
                static::valueToString($value),
960 8
                \implode(', ', \array_map(array('static', 'valueToString'), $values))
961
            ));
962
        }
963 8
    }
964
965
    /**
966
     * @psalm-pure
967
     *
968
     * @param string $value
969
     * @param string $subString
970
     * @param string $message
971
     *
972
     * @throws InvalidArgumentException
973
     */
974 80 View Code Duplication
    public static function contains($value, $subString, $message = '')
975
    {
976 80
        if (false === \strpos($value, $subString)) {
977 32
            static::reportInvalidArgument(\sprintf(
978 32
                $message ?: 'Expected a value to contain %2$s. Got: %s',
979 32
                static::valueToString($value),
980 32
                static::valueToString($subString)
981
            ));
982
        }
983 48
    }
984
985
    /**
986
     * @psalm-pure
987
     *
988
     * @param string $value
989
     * @param string $subString
990
     * @param string $message
991
     *
992
     * @throws InvalidArgumentException
993
     */
994 80 View Code Duplication
    public static function notContains($value, $subString, $message = '')
995
    {
996 80
        if (false !== \strpos($value, $subString)) {
997 48
            static::reportInvalidArgument(\sprintf(
998 48
                $message ?: '%2$s was not expected to be contained in a value. Got: %s',
999 48
                static::valueToString($value),
1000 48
                static::valueToString($subString)
1001
            ));
1002
        }
1003 32
    }
1004
1005
    /**
1006
     * @psalm-pure
1007
     *
1008
     * @param string $value
1009
     * @param string $message
1010
     *
1011
     * @throws InvalidArgumentException
1012
     */
1013 40
    public static function notWhitespaceOnly($value, $message = '')
1014
    {
1015 40
        if (\preg_match('/^\s*$/', $value)) {
1016 24
            static::reportInvalidArgument(\sprintf(
1017 24
                $message ?: 'Expected a non-whitespace string. Got: %s',
1018 24
                static::valueToString($value)
1019
            ));
1020
        }
1021 16
    }
1022
1023
    /**
1024
     * @psalm-pure
1025
     *
1026
     * @param string $value
1027
     * @param string $prefix
1028
     * @param string $message
1029
     *
1030
     * @throws InvalidArgumentException
1031
     */
1032 48 View Code Duplication
    public static function startsWith($value, $prefix, $message = '')
1033
    {
1034 48
        if (0 !== \strpos($value, $prefix)) {
1035 32
            static::reportInvalidArgument(\sprintf(
1036 32
                $message ?: 'Expected a value to start with %2$s. Got: %s',
1037 32
                static::valueToString($value),
1038 32
                static::valueToString($prefix)
1039
            ));
1040
        }
1041 16
    }
1042
1043
    /**
1044
     * @psalm-pure
1045
     *
1046
     * @param string $value
1047
     * @param string $prefix
1048
     * @param string $message
1049
     *
1050
     * @throws InvalidArgumentException
1051
     */
1052 48 View Code Duplication
    public static function notStartsWith($value, $prefix, $message = '')
1053
    {
1054 48
        if (0 === \strpos($value, $prefix)) {
1055 16
            static::reportInvalidArgument(\sprintf(
1056 16
                $message ?: 'Expected a value not to start with %2$s. Got: %s',
1057 16
                static::valueToString($value),
1058 16
                static::valueToString($prefix)
1059
            ));
1060
        }
1061 32
    }
1062
1063
    /**
1064
     * @psalm-pure
1065
     *
1066
     * @param mixed  $value
1067
     * @param string $message
1068
     *
1069
     * @throws InvalidArgumentException
1070
     */
1071 35
    public static function startsWithLetter($value, $message = '')
1072
    {
1073 35
        static::string($value);
1074
1075 24
        $valid = isset($value[0]);
1076
1077 24
        if ($valid) {
1078 20
            $locale = \setlocale(LC_CTYPE, 0);
1079 20
            \setlocale(LC_CTYPE, 'C');
1080 20
            $valid = \ctype_alpha($value[0]);
1081 20
            \setlocale(LC_CTYPE, $locale);
1082
        }
1083
1084 24
        if (!$valid) {
1085 12
            static::reportInvalidArgument(\sprintf(
1086 12
                $message ?: 'Expected a value to start with a letter. Got: %s',
1087 12
                static::valueToString($value)
1088
            ));
1089
        }
1090 12
    }
1091
1092
    /**
1093
     * @psalm-pure
1094
     *
1095
     * @param string $value
1096
     * @param string $suffix
1097
     * @param string $message
1098
     *
1099
     * @throws InvalidArgumentException
1100
     */
1101 48 View Code Duplication
    public static function endsWith($value, $suffix, $message = '')
1102
    {
1103 48
        if ($suffix !== \substr($value, -\strlen($suffix))) {
1104 32
            static::reportInvalidArgument(\sprintf(
1105 32
                $message ?: 'Expected a value to end with %2$s. Got: %s',
1106 32
                static::valueToString($value),
1107 32
                static::valueToString($suffix)
1108
            ));
1109
        }
1110 16
    }
1111
1112
    /**
1113
     * @psalm-pure
1114
     *
1115
     * @param string $value
1116
     * @param string $suffix
1117
     * @param string $message
1118
     *
1119
     * @throws InvalidArgumentException
1120
     */
1121 48 View Code Duplication
    public static function notEndsWith($value, $suffix, $message = '')
1122
    {
1123 48
        if ($suffix === \substr($value, -\strlen($suffix))) {
1124 16
            static::reportInvalidArgument(\sprintf(
1125 16
                $message ?: 'Expected a value not to end with %2$s. Got: %s',
1126 16
                static::valueToString($value),
1127 16
                static::valueToString($suffix)
1128
            ));
1129
        }
1130 32
    }
1131
1132
    /**
1133
     * @psalm-pure
1134
     *
1135
     * @param string $value
1136
     * @param string $pattern
1137
     * @param string $message
1138
     *
1139
     * @throws InvalidArgumentException
1140
     */
1141 12
    public static function regex($value, $pattern, $message = '')
1142
    {
1143 12
        if (!\preg_match($pattern, $value)) {
1144 8
            static::reportInvalidArgument(\sprintf(
1145 8
                $message ?: 'The value %s does not match the expected pattern.',
1146 8
                static::valueToString($value)
1147
            ));
1148
        }
1149 4
    }
1150
1151
    /**
1152
     * @psalm-pure
1153
     *
1154
     * @param string $value
1155
     * @param string $pattern
1156
     * @param string $message
1157
     *
1158
     * @throws InvalidArgumentException
1159
     */
1160 12
    public static function notRegex($value, $pattern, $message = '')
1161
    {
1162 12
        if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
1163 4
            static::reportInvalidArgument(\sprintf(
1164 4
                $message ?: 'The value %s matches the pattern %s (at offset %d).',
1165 4
                static::valueToString($value),
1166 4
                static::valueToString($pattern),
1167 4
                $matches[0][1]
1168
            ));
1169
        }
1170 8
    }
1171
1172
    /**
1173
     * @psalm-pure
1174
     *
1175
     * @param mixed  $value
1176
     * @param string $message
1177
     *
1178
     * @throws InvalidArgumentException
1179
     */
1180 28 View Code Duplication
    public static function unicodeLetters($value, $message = '')
1181
    {
1182 28
        static::string($value);
1183
1184 28
        if (!\preg_match('/^\p{L}+$/u', $value)) {
1185 16
            static::reportInvalidArgument(\sprintf(
1186 16
                $message ?: 'Expected a value to contain only Unicode letters. Got: %s',
1187 16
                static::valueToString($value)
1188
            ));
1189
        }
1190 12
    }
1191
1192
    /**
1193
     * @psalm-pure
1194
     *
1195
     * @param mixed  $value
1196
     * @param string $message
1197
     *
1198
     * @throws InvalidArgumentException
1199
     */
1200 20 View Code Duplication
    public static function alpha($value, $message = '')
1201
    {
1202 20
        static::string($value);
1203
1204 12
        $locale = \setlocale(LC_CTYPE, 0);
1205 12
        \setlocale(LC_CTYPE, 'C');
1206 12
        $valid = !\ctype_alpha($value);
1207 12
        \setlocale(LC_CTYPE, $locale);
1208
1209 12
        if ($valid) {
1210 8
            static::reportInvalidArgument(\sprintf(
1211 8
                $message ?: 'Expected a value to contain only letters. Got: %s',
1212 8
                static::valueToString($value)
1213
            ));
1214
        }
1215 4
    }
1216
1217
    /**
1218
     * @psalm-pure
1219
     *
1220
     * @param string $value
1221
     * @param string $message
1222
     *
1223
     * @throws InvalidArgumentException
1224
     */
1225 12 View Code Duplication
    public static function digits($value, $message = '')
1226
    {
1227 12
        $locale = \setlocale(LC_CTYPE, 0);
1228 12
        \setlocale(LC_CTYPE, 'C');
1229 12
        $valid = !\ctype_digit($value);
1230 12
        \setlocale(LC_CTYPE, $locale);
1231
1232 12
        if ($valid) {
1233 8
            static::reportInvalidArgument(\sprintf(
1234 8
                $message ?: 'Expected a value to contain digits only. Got: %s',
1235 8
                static::valueToString($value)
1236
            ));
1237
        }
1238 4
    }
1239
1240
    /**
1241
     * @psalm-pure
1242
     *
1243
     * @param string $value
1244
     * @param string $message
1245
     *
1246
     * @throws InvalidArgumentException
1247
     */
1248 12 View Code Duplication
    public static function alnum($value, $message = '')
1249
    {
1250 12
        $locale = \setlocale(LC_CTYPE, 0);
1251 12
        \setlocale(LC_CTYPE, 'C');
1252 12
        $valid = !\ctype_alnum($value);
1253 12
        \setlocale(LC_CTYPE, $locale);
1254
1255 12
        if ($valid) {
1256 8
            static::reportInvalidArgument(\sprintf(
1257 8
                $message ?: 'Expected a value to contain letters and digits only. Got: %s',
1258 8
                static::valueToString($value)
1259
            ));
1260
        }
1261 4
    }
1262
1263
    /**
1264
     * @psalm-pure
1265
     * @psalm-assert lowercase-string $value
1266
     *
1267
     * @param string $value
1268
     * @param string $message
1269
     *
1270
     * @throws InvalidArgumentException
1271
     */
1272 16 View Code Duplication
    public static function lower($value, $message = '')
1273
    {
1274 16
        $locale = \setlocale(LC_CTYPE, 0);
1275 16
        \setlocale(LC_CTYPE, 'C');
1276 16
        $valid = !\ctype_lower($value);
1277 16
        \setlocale(LC_CTYPE, $locale);
1278
1279 16
        if ($valid) {
1280 12
            static::reportInvalidArgument(\sprintf(
1281 12
                $message ?: 'Expected a value to contain lowercase characters only. Got: %s',
1282 12
                static::valueToString($value)
1283
            ));
1284
        }
1285 4
    }
1286
1287
    /**
1288
     * @psalm-pure
1289
     * @psalm-assert !lowercase-string $value
1290
     *
1291
     * @param string $value
1292
     * @param string $message
1293
     *
1294
     * @throws InvalidArgumentException
1295
     */
1296 16 View Code Duplication
    public static function upper($value, $message = '')
1297
    {
1298 16
        $locale = \setlocale(LC_CTYPE, 0);
1299 16
        \setlocale(LC_CTYPE, 'C');
1300 16
        $valid = !\ctype_upper($value);
1301 16
        \setlocale(LC_CTYPE, $locale);
1302
1303 16
        if ($valid) {
1304 12
            static::reportInvalidArgument(\sprintf(
1305 12
                $message ?: 'Expected a value to contain uppercase characters only. Got: %s',
1306 12
                static::valueToString($value)
1307
            ));
1308
        }
1309 4
    }
1310
1311
    /**
1312
     * @psalm-pure
1313
     *
1314
     * @param string $value
1315
     * @param int    $length
1316
     * @param string $message
1317
     *
1318
     * @throws InvalidArgumentException
1319
     */
1320 36
    public static function length($value, $length, $message = '')
1321
    {
1322 36
        if ($length !== static::strlen($value)) {
1323 24
            static::reportInvalidArgument(\sprintf(
1324 24
                $message ?: 'Expected a value to contain %2$s characters. Got: %s',
1325 24
                static::valueToString($value),
1326 24
                $length
1327
            ));
1328
        }
1329 12
    }
1330
1331
    /**
1332
     * Inclusive min.
1333
     *
1334
     * @psalm-pure
1335
     *
1336
     * @param string    $value
1337
     * @param int|float $min
1338
     * @param string    $message
1339
     *
1340
     * @throws InvalidArgumentException
1341
     */
1342 36
    public static function minLength($value, $min, $message = '')
1343
    {
1344 36
        if (static::strlen($value) < $min) {
1345 12
            static::reportInvalidArgument(\sprintf(
1346 12
                $message ?: 'Expected a value to contain at least %2$s characters. Got: %s',
1347 12
                static::valueToString($value),
1348 12
                $min
1349
            ));
1350
        }
1351 24
    }
1352
1353
    /**
1354
     * Inclusive max.
1355
     *
1356
     * @psalm-pure
1357
     *
1358
     * @param string    $value
1359
     * @param int|float $max
1360
     * @param string    $message
1361
     *
1362
     * @throws InvalidArgumentException
1363
     */
1364 36
    public static function maxLength($value, $max, $message = '')
1365
    {
1366 36
        if (static::strlen($value) > $max) {
1367 12
            static::reportInvalidArgument(\sprintf(
1368 12
                $message ?: 'Expected a value to contain at most %2$s characters. Got: %s',
1369 12
                static::valueToString($value),
1370 12
                $max
1371
            ));
1372
        }
1373 24
    }
1374
1375
    /**
1376
     * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion.
1377
     *
1378
     * @psalm-pure
1379
     *
1380
     * @param string    $value
1381
     * @param int|float $min
1382
     * @param int|float $max
1383
     * @param string    $message
1384
     *
1385
     * @throws InvalidArgumentException
1386
     */
1387 60 View Code Duplication
    public static function lengthBetween($value, $min, $max, $message = '')
1388
    {
1389 60
        $length = static::strlen($value);
1390
1391 60
        if ($length < $min || $length > $max) {
1392 24
            static::reportInvalidArgument(\sprintf(
1393 24
                $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s',
1394 24
                static::valueToString($value),
1395 24
                $min,
1396 24
                $max
1397
            ));
1398
        }
1399 36
    }
1400
1401
    /**
1402
     * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file.
1403
     *
1404
     * @param mixed  $value
1405
     * @param string $message
1406
     *
1407
     * @throws InvalidArgumentException
1408
     */
1409 36 View Code Duplication
    public static function fileExists($value, $message = '')
1410
    {
1411 36
        static::string($value);
1412
1413 36
        if (!\file_exists($value)) {
1414 12
            static::reportInvalidArgument(\sprintf(
1415 12
                $message ?: 'The file %s does not exist.',
1416 12
                static::valueToString($value)
1417
            ));
1418
        }
1419 24
    }
1420
1421
    /**
1422
     * @param mixed  $value
1423
     * @param string $message
1424
     *
1425
     * @throws InvalidArgumentException
1426
     */
1427 12 View Code Duplication
    public static function file($value, $message = '')
1428
    {
1429 12
        static::fileExists($value, $message);
1430
1431 8
        if (!\is_file($value)) {
1432 4
            static::reportInvalidArgument(\sprintf(
1433 4
                $message ?: 'The path %s is not a file.',
1434 4
                static::valueToString($value)
1435
            ));
1436
        }
1437 4
    }
1438
1439
    /**
1440
     * @param mixed  $value
1441
     * @param string $message
1442
     *
1443
     * @throws InvalidArgumentException
1444
     */
1445 12 View Code Duplication
    public static function directory($value, $message = '')
1446
    {
1447 12
        static::fileExists($value, $message);
1448
1449 8
        if (!\is_dir($value)) {
1450 4
            static::reportInvalidArgument(\sprintf(
1451 4
                $message ?: 'The path %s is no directory.',
1452 4
                static::valueToString($value)
1453
            ));
1454
        }
1455 4
    }
1456
1457
    /**
1458
     * @param string $value
1459
     * @param string $message
1460
     *
1461
     * @throws InvalidArgumentException
1462
     */
1463
    public static function readable($value, $message = '')
1464
    {
1465
        if (!\is_readable($value)) {
1466
            static::reportInvalidArgument(\sprintf(
1467
                $message ?: 'The path %s is not readable.',
1468
                static::valueToString($value)
1469
            ));
1470
        }
1471
    }
1472
1473
    /**
1474
     * @param string $value
1475
     * @param string $message
1476
     *
1477
     * @throws InvalidArgumentException
1478
     */
1479
    public static function writable($value, $message = '')
1480
    {
1481
        if (!\is_writable($value)) {
1482
            static::reportInvalidArgument(\sprintf(
1483
                $message ?: 'The path %s is not writable.',
1484
                static::valueToString($value)
1485
            ));
1486
        }
1487
    }
1488
1489
    /**
1490
     * @psalm-assert class-string $value
1491
     *
1492
     * @param mixed  $value
1493
     * @param string $message
1494
     *
1495
     * @throws InvalidArgumentException
1496
     */
1497 8
    public static function classExists($value, $message = '')
1498
    {
1499 8
        if (!\class_exists($value)) {
1500 4
            static::reportInvalidArgument(\sprintf(
1501 4
                $message ?: 'Expected an existing class name. Got: %s',
1502 4
                static::valueToString($value)
1503
            ));
1504
        }
1505 4
    }
1506
1507
    /**
1508
     * @psalm-pure
1509
     * @psalm-template ExpectedType of object
1510
     * @psalm-param class-string<ExpectedType> $class
1511
     * @psalm-assert class-string<ExpectedType>|ExpectedType $value
1512
     *
1513
     * @param mixed         $value
1514
     * @param string|object $class
1515
     * @param string        $message
1516
     *
1517
     * @throws InvalidArgumentException
1518
     */
1519 8
    public static function subclassOf($value, $class, $message = '')
1520
    {
1521 8
        if (!\is_subclass_of($value, $class)) {
1522 4
            static::reportInvalidArgument(\sprintf(
1523 4
                $message ?: 'Expected a sub-class of %2$s. Got: %s',
1524 4
                static::valueToString($value),
1525 4
                static::valueToString($class)
1526
            ));
1527
        }
1528 4
    }
1529
1530
    /**
1531
     * @psalm-assert class-string $value
1532
     *
1533
     * @param mixed  $value
1534
     * @param string $message
1535
     *
1536
     * @throws InvalidArgumentException
1537
     */
1538 8
    public static function interfaceExists($value, $message = '')
1539
    {
1540 8
        if (!\interface_exists($value)) {
1541 4
            static::reportInvalidArgument(\sprintf(
1542 4
                $message ?: 'Expected an existing interface name. got %s',
1543 4
                static::valueToString($value)
1544
            ));
1545
        }
1546 4
    }
1547
1548
    /**
1549
     * @psalm-pure
1550
     * @psalm-template ExpectedType of object
1551
     * @psalm-param class-string<ExpectedType> $interface
1552
     * @psalm-assert class-string<ExpectedType> $value
1553
     *
1554
     * @param mixed  $value
1555
     * @param mixed  $interface
1556
     * @param string $message
1557
     *
1558
     * @throws InvalidArgumentException
1559
     */
1560 8 View Code Duplication
    public static function implementsInterface($value, $interface, $message = '')
1561
    {
1562 8
        if (!\in_array($interface, \class_implements($value))) {
1563 4
            static::reportInvalidArgument(\sprintf(
1564 4
                $message ?: 'Expected an implementation of %2$s. Got: %s',
1565 4
                static::valueToString($value),
1566 4
                static::valueToString($interface)
1567
            ));
1568
        }
1569 4
    }
1570
1571
    /**
1572
     * @psalm-pure
1573
     * @psalm-param class-string|object $classOrObject
1574
     *
1575
     * @param string|object $classOrObject
1576
     * @param mixed         $property
1577
     * @param string        $message
1578
     *
1579
     * @throws InvalidArgumentException
1580
     */
1581 12 View Code Duplication
    public static function propertyExists($classOrObject, $property, $message = '')
1582
    {
1583 12
        if (!\property_exists($classOrObject, $property)) {
1584 4
            static::reportInvalidArgument(\sprintf(
1585 4
                $message ?: 'Expected the property %s to exist.',
1586 4
                static::valueToString($property)
1587
            ));
1588
        }
1589 8
    }
1590
1591
    /**
1592
     * @psalm-pure
1593
     * @psalm-param class-string|object $classOrObject
1594
     *
1595
     * @param string|object $classOrObject
1596
     * @param mixed         $property
1597
     * @param string        $message
1598
     *
1599
     * @throws InvalidArgumentException
1600
     */
1601 12 View Code Duplication
    public static function propertyNotExists($classOrObject, $property, $message = '')
1602
    {
1603 12
        if (\property_exists($classOrObject, $property)) {
1604 8
            static::reportInvalidArgument(\sprintf(
1605 8
                $message ?: 'Expected the property %s to not exist.',
1606 8
                static::valueToString($property)
1607
            ));
1608
        }
1609 4
    }
1610
1611
    /**
1612
     * @psalm-pure
1613
     * @psalm-param class-string|object $classOrObject
1614
     *
1615
     * @param string|object $classOrObject
1616
     * @param mixed         $method
1617
     * @param string        $message
1618
     *
1619
     * @throws InvalidArgumentException
1620
     */
1621 27 View Code Duplication
    public static function methodExists($classOrObject, $method, $message = '')
1622
    {
1623 27
        if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) {
1624 19
            static::reportInvalidArgument(\sprintf(
1625 19
                $message ?: 'Expected the method %s to exist.',
1626 19
                static::valueToString($method)
1627
            ));
1628
        }
1629 8
    }
1630
1631
    /**
1632
     * @psalm-pure
1633
     * @psalm-param class-string|object $classOrObject
1634
     *
1635
     * @param string|object $classOrObject
1636
     * @param mixed         $method
1637
     * @param string        $message
1638
     *
1639
     * @throws InvalidArgumentException
1640
     */
1641 27 View Code Duplication
    public static function methodNotExists($classOrObject, $method, $message = '')
1642
    {
1643 27
        if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) {
1644 8
            static::reportInvalidArgument(\sprintf(
1645 8
                $message ?: 'Expected the method %s to not exist.',
1646 8
                static::valueToString($method)
1647
            ));
1648
        }
1649 19
    }
1650
1651
    /**
1652
     * @psalm-pure
1653
     *
1654
     * @param array      $array
1655
     * @param string|int $key
1656
     * @param string     $message
1657
     *
1658
     * @throws InvalidArgumentException
1659
     */
1660 12 View Code Duplication
    public static function keyExists($array, $key, $message = '')
1661
    {
1662 12
        if (!(isset($array[$key]) || \array_key_exists($key, $array))) {
1663 4
            static::reportInvalidArgument(\sprintf(
1664 4
                $message ?: 'Expected the key %s to exist.',
1665 4
                static::valueToString($key)
1666
            ));
1667
        }
1668 8
    }
1669
1670
    /**
1671
     * @psalm-pure
1672
     *
1673
     * @param array      $array
1674
     * @param string|int $key
1675
     * @param string     $message
1676
     *
1677
     * @throws InvalidArgumentException
1678
     */
1679 12 View Code Duplication
    public static function keyNotExists($array, $key, $message = '')
1680
    {
1681 12
        if (isset($array[$key]) || \array_key_exists($key, $array)) {
1682 8
            static::reportInvalidArgument(\sprintf(
1683 8
                $message ?: 'Expected the key %s to not exist.',
1684 8
                static::valueToString($key)
1685
            ));
1686
        }
1687 4
    }
1688
1689
    /**
1690
     * Checks if a value is a valid array key (int or string).
1691
     *
1692
     * @psalm-pure
1693
     * @psalm-assert array-key $value
1694
     *
1695
     * @param mixed  $value
1696
     * @param string $message
1697
     *
1698
     * @throws InvalidArgumentException
1699
     */
1700 28
    public static function validArrayKey($value, $message = '')
1701
    {
1702 28
        if (!(\is_int($value) || \is_string($value))) {
1703 20
            static::reportInvalidArgument(\sprintf(
1704 20
                $message ?: 'Expected string or integer. Got: %s',
1705 20
                static::typeToString($value)
1706
            ));
1707
        }
1708 8
    }
1709
1710
    /**
1711
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1712
     *
1713
     * @param Countable|array $array
1714
     * @param int             $number
1715
     * @param string          $message
1716
     *
1717
     * @throws InvalidArgumentException
1718
     */
1719 8
    public static function count($array, $number, $message = '')
1720
    {
1721 8
        static::eq(
1722 8
            \count($array),
1723
            $number,
1724 8
            \sprintf(
1725 8
                $message ?: 'Expected an array to contain %d elements. Got: %d.',
1726 8
                $number,
1727 8
                \count($array)
1728
            )
1729
        );
1730 4
    }
1731
1732
    /**
1733
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1734
     *
1735
     * @param Countable|array $array
1736
     * @param int|float       $min
1737
     * @param string          $message
1738
     *
1739
     * @throws InvalidArgumentException
1740
     */
1741 12 View Code Duplication
    public static function minCount($array, $min, $message = '')
1742
    {
1743 12
        if (\count($array) < $min) {
1744 4
            static::reportInvalidArgument(\sprintf(
1745 4
                $message ?: 'Expected an array to contain at least %2$d elements. Got: %d',
1746 4
                \count($array),
1747 4
                $min
1748
            ));
1749
        }
1750 8
    }
1751
1752
    /**
1753
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1754
     *
1755
     * @param Countable|array $array
1756
     * @param int|float       $max
1757
     * @param string          $message
1758
     *
1759
     * @throws InvalidArgumentException
1760
     */
1761 12 View Code Duplication
    public static function maxCount($array, $max, $message = '')
1762
    {
1763 12
        if (\count($array) > $max) {
1764 4
            static::reportInvalidArgument(\sprintf(
1765 4
                $message ?: 'Expected an array to contain at most %2$d elements. Got: %d',
1766 4
                \count($array),
1767 4
                $max
1768
            ));
1769
        }
1770 8
    }
1771
1772
    /**
1773
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1774
     *
1775
     * @param Countable|array $array
1776
     * @param int|float       $min
1777
     * @param int|float       $max
1778
     * @param string          $message
1779
     *
1780
     * @throws InvalidArgumentException
1781
     */
1782 20
    public static function countBetween($array, $min, $max, $message = '')
1783
    {
1784 20
        $count = \count($array);
1785
1786 20
        if ($count < $min || $count > $max) {
1787 8
            static::reportInvalidArgument(\sprintf(
1788 8
                $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d',
1789 8
                $count,
1790 8
                $min,
1791 8
                $max
1792
            ));
1793
        }
1794 12
    }
1795
1796
    /**
1797
     * @psalm-pure
1798
     * @psalm-assert list $array
1799
     *
1800
     * @param mixed  $array
1801
     * @param string $message
1802
     *
1803
     * @throws InvalidArgumentException
1804
     */
1805 80 View Code Duplication
    public static function isList($array, $message = '')
1806
    {
1807 80
        if (!\is_array($array) || $array !== \array_values($array)) {
1808 32
            static::reportInvalidArgument(
1809 32
                $message ?: 'Expected list - non-associative array.'
1810
            );
1811
        }
1812 48
    }
1813
1814
    /**
1815
     * @psalm-pure
1816
     * @psalm-assert non-empty-list $array
1817
     *
1818
     * @param mixed  $array
1819
     * @param string $message
1820
     *
1821
     * @throws InvalidArgumentException
1822
     */
1823 40
    public static function isNonEmptyList($array, $message = '')
1824
    {
1825 40
        static::isList($array, $message);
1826 24
        static::notEmpty($array, $message);
1827 20
    }
1828
1829
    /**
1830
     * @psalm-pure
1831
     * @psalm-template T
1832
     * @psalm-param mixed|array<T> $array
1833
     * @psalm-assert array<string, T> $array
1834
     *
1835
     * @param mixed  $array
1836
     * @param string $message
1837
     *
1838
     * @throws InvalidArgumentException
1839
     */
1840 32
    public static function isMap($array, $message = '')
1841
    {
1842
        if (
1843 32
            !\is_array($array) ||
1844 32
            \array_keys($array) !== \array_filter(\array_keys($array), '\is_string')
1845
        ) {
1846 16
            static::reportInvalidArgument(
1847 16
                $message ?: 'Expected map - associative array with string keys.'
1848
            );
1849
        }
1850 16
    }
1851
1852
    /**
1853
     * @psalm-pure
1854
     * @psalm-template T
1855
     * @psalm-param mixed|array<T> $array
1856
     * @psalm-assert array<string, T> $array
1857
     * @psalm-assert !empty $array
1858
     *
1859
     * @param mixed  $array
1860
     * @param string $message
1861
     *
1862
     * @throws InvalidArgumentException
1863
     */
1864 16
    public static function isNonEmptyMap($array, $message = '')
1865
    {
1866 16
        static::isMap($array, $message);
1867 8
        static::notEmpty($array, $message);
1868 4
    }
1869
1870
    /**
1871
     * @psalm-pure
1872
     *
1873
     * @param string $value
1874
     * @param string $message
1875
     *
1876
     * @throws InvalidArgumentException
1877
     */
1878 56
    public static function uuid($value, $message = '')
1879
    {
1880 56
        $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value);
1881
1882
        // The nil UUID is special form of UUID that is specified to have all
1883
        // 128 bits set to zero.
1884 56
        if ('00000000-0000-0000-0000-000000000000' === $value) {
1885 4
            return;
1886
        }
1887
1888 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)) {
1889 20
            static::reportInvalidArgument(\sprintf(
1890 20
                $message ?: 'Value %s is not a valid UUID.',
1891 20
                static::valueToString($value)
1892
            ));
1893
        }
1894 32
    }
1895
1896
    /**
1897
     * @psalm-param class-string<Throwable> $class
1898
     *
1899
     * @param Closure $expression
1900
     * @param string  $class
1901
     * @param string  $message
1902
     *
1903
     * @throws InvalidArgumentException
1904
     */
1905 24
    public static function throws(Closure $expression, $class = 'Exception', $message = '')
1906
    {
1907 24
        static::string($class);
1908
1909 24
        $actual = 'none';
1910
1911
        try {
1912 24
            $expression();
1913 24
        } catch (Exception $e) {
1914 20
            $actual = \get_class($e);
1915 20
            if ($e instanceof $class) {
1916 20
                return;
1917
            }
1918 4
        } catch (Throwable $e) {
0 ignored issues
show
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...
1919 4
            $actual = \get_class($e);
1920 4
            if ($e instanceof $class) {
1921 4
                return;
1922
            }
1923
        }
1924
1925 8
        static::reportInvalidArgument($message ?: \sprintf(
1926
            'Expected to throw "%s", got "%s"',
1927 8
            $class,
1928 8
            $actual
1929
        ));
1930
    }
1931
1932
    /**
1933
     * @throws BadMethodCallException
1934
     */
1935 1642
    public static function __callStatic($name, $arguments)
1936
    {
1937 1642
        if ('nullOr' === \substr($name, 0, 6)) {
1938 607
            if (null !== $arguments[0]) {
1939 501
                $method = \lcfirst(\substr($name, 6));
1940 501
                \call_user_func_array(array('static', $method), $arguments);
1941
            }
1942
1943 354
            return;
1944
        }
1945
1946 1035
        if ('all' === \substr($name, 0, 3)) {
1947 1034
            static::isIterable($arguments[0]);
1948
1949 1034
            $method = \lcfirst(\substr($name, 3));
1950 1034
            $args = $arguments;
1951
1952 1034
            foreach ($arguments[0] as $entry) {
1953 1034
                $args[0] = $entry;
1954
1955 1034
                \call_user_func_array(array('static', $method), $args);
1956
            }
1957
1958 504
            return;
1959
        }
1960
1961 1
        throw new BadMethodCallException('No such method: '.$name);
1962
    }
1963
1964
    /**
1965
     * @param mixed $value
1966
     *
1967
     * @return string
1968
     */
1969 751
    protected static function valueToString($value)
1970
    {
1971 751
        if (null === $value) {
1972 20
            return 'null';
1973
        }
1974
1975 733
        if (true === $value) {
1976 15
            return 'true';
1977
        }
1978
1979 723
        if (false === $value) {
1980 25
            return 'false';
1981
        }
1982
1983 698
        if (\is_array($value)) {
1984 21
            return 'array';
1985
        }
1986
1987 677
        if (\is_object($value)) {
1988 3
            if (\method_exists($value, '__toString')) {
1989 1
                return \get_class($value).': '.self::valueToString($value->__toString());
1990
            }
1991
1992 2
            if ($value instanceof DateTime || $value instanceof DateTimeImmutable) {
1993 1
                return \get_class($value).': '.self::valueToString($value->format('c'));
1994
            }
1995
1996 1
            return \get_class($value);
1997
        }
1998
1999 676
        if (\is_resource($value)) {
2000 1
            return 'resource';
2001
        }
2002
2003 676
        if (\is_string($value)) {
2004 574
            return '"'.$value.'"';
2005
        }
2006
2007 114
        return (string) $value;
2008
    }
2009
2010
    /**
2011
     * @param mixed $value
2012
     *
2013
     * @return string
2014
     */
2015 251
    protected static function typeToString($value)
2016
    {
2017 251
        return \is_object($value) ? \get_class($value) : \gettype($value);
2018
    }
2019
2020 168
    protected static function strlen($value)
2021
    {
2022 168
        if (!\function_exists('mb_detect_encoding')) {
2023
            return \strlen($value);
2024
        }
2025
2026 168
        if (false === $encoding = \mb_detect_encoding($value)) {
2027
            return \strlen($value);
2028
        }
2029
2030 168
        return \mb_strlen($value, $encoding);
2031
    }
2032
2033
    /**
2034
     * @param string $message
2035
     *
2036
     * @throws InvalidArgumentException
2037
     *
2038
     * @psalm-pure this method is not supposed to perform side-effects
2039
     */
2040 1065
    protected static function reportInvalidArgument($message)
2041
    {
2042 1065
        throw new InvalidArgumentException($message);
2043
    }
2044
2045
    private function __construct()
2046
    {
2047
    }
2048
}
2049