cloudflare/Cloudflare-WordPress

Public

mirrored fromhttps://github.com/cloudflare/Cloudflare-WordPress

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0340e6fe28c7d8d779f0a71ce4819b82baedf260

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

vendor/webmozart/assert/src/Assert.php

2048lines · modecode

1<?php
2
3/*
4 * This file is part of the webmozart/assert package.
5 *
6 * (c) Bernhard Schussek <bschussek@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Webmozart\Assert;
13
14use ArrayAccess;
15use BadMethodCallException;
16use Closure;
17use Countable;
18use DateTime;
19use DateTimeImmutable;
20use Exception;
21use InvalidArgumentException;
22use ResourceBundle;
23use SimpleXMLElement;
24use Throwable;
25use 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 <bschussek@gmail.com>
35 */
36class 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 public static function string($value, $message = '')
48 {
49 if (!\is_string($value)) {
50 static::reportInvalidArgument(\sprintf(
51 $message ?: 'Expected a string. Got: %s',
52 static::typeToString($value)
53 ));
54 }
55 }
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 public static function stringNotEmpty($value, $message = '')
67 {
68 static::string($value, $message);
69 static::notEq($value, '', $message);
70 }
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 public static function integer($value, $message = '')
82 {
83 if (!\is_int($value)) {
84 static::reportInvalidArgument(\sprintf(
85 $message ?: 'Expected an integer. Got: %s',
86 static::typeToString($value)
87 ));
88 }
89 }
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 public static function integerish($value, $message = '')
101 {
102 if (!\is_numeric($value) || $value != (int) $value) {
103 static::reportInvalidArgument(\sprintf(
104 $message ?: 'Expected an integerish value. Got: %s',
105 static::typeToString($value)
106 ));
107 }
108 }
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 public static function float($value, $message = '')
120 {
121 if (!\is_float($value)) {
122 static::reportInvalidArgument(\sprintf(
123 $message ?: 'Expected a float. Got: %s',
124 static::typeToString($value)
125 ));
126 }
127 }
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 public static function numeric($value, $message = '')
139 {
140 if (!\is_numeric($value)) {
141 static::reportInvalidArgument(\sprintf(
142 $message ?: 'Expected a numeric. Got: %s',
143 static::typeToString($value)
144 ));
145 }
146 }
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 public static function natural($value, $message = '')
158 {
159 if (!\is_int($value) || $value < 0) {
160 static::reportInvalidArgument(\sprintf(
161 $message ?: 'Expected a non-negative integer. Got: %s',
162 static::valueToString($value)
163 ));
164 }
165 }
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 public static function boolean($value, $message = '')
177 {
178 if (!\is_bool($value)) {
179 static::reportInvalidArgument(\sprintf(
180 $message ?: 'Expected a boolean. Got: %s',
181 static::typeToString($value)
182 ));
183 }
184 }
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 public static function scalar($value, $message = '')
196 {
197 if (!\is_scalar($value)) {
198 static::reportInvalidArgument(\sprintf(
199 $message ?: 'Expected a scalar. Got: %s',
200 static::typeToString($value)
201 ));
202 }
203 }
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 public static function object($value, $message = '')
215 {
216 if (!\is_object($value)) {
217 static::reportInvalidArgument(\sprintf(
218 $message ?: 'Expected an object. Got: %s',
219 static::typeToString($value)
220 ));
221 }
222 }
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 public static function resource($value, $type = null, $message = '')
235 {
236 if (!\is_resource($value)) {
237 static::reportInvalidArgument(\sprintf(
238 $message ?: 'Expected a resource. Got: %s',
239 static::typeToString($value)
240 ));
241 }
242
243 if ($type && $type !== \get_resource_type($value)) {
244 static::reportInvalidArgument(\sprintf(
245 $message ?: 'Expected a resource of type %2$s. Got: %s',
246 static::typeToString($value),
247 $type
248 ));
249 }
250 }
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 public static function isCallable($value, $message = '')
262 {
263 if (!\is_callable($value)) {
264 static::reportInvalidArgument(\sprintf(
265 $message ?: 'Expected a callable. Got: %s',
266 static::typeToString($value)
267 ));
268 }
269 }
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 public static function isArray($value, $message = '')
281 {
282 if (!\is_array($value)) {
283 static::reportInvalidArgument(\sprintf(
284 $message ?: 'Expected an array. Got: %s',
285 static::typeToString($value)
286 ));
287 }
288 }
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 public static function isTraversable($value, $message = '')
302 {
303 @\trigger_error(
304 \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 __METHOD__
307 ),
308 \E_USER_DEPRECATED
309 );
310
311 if (!\is_array($value) && !($value instanceof Traversable)) {
312 static::reportInvalidArgument(\sprintf(
313 $message ?: 'Expected a traversable. Got: %s',
314 static::typeToString($value)
315 ));
316 }
317 }
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 public static function isArrayAccessible($value, $message = '')
329 {
330 if (!\is_array($value) && !($value instanceof ArrayAccess)) {
331 static::reportInvalidArgument(\sprintf(
332 $message ?: 'Expected an array accessible. Got: %s',
333 static::typeToString($value)
334 ));
335 }
336 }
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 public static function isCountable($value, $message = '')
348 {
349 if (
350 !\is_array($value)
351 && !($value instanceof Countable)
352 && !($value instanceof ResourceBundle)
353 && !($value instanceof SimpleXMLElement)
354 ) {
355 static::reportInvalidArgument(\sprintf(
356 $message ?: 'Expected a countable. Got: %s',
357 static::typeToString($value)
358 ));
359 }
360 }
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 public static function isIterable($value, $message = '')
372 {
373 if (!\is_array($value) && !($value instanceof Traversable)) {
374 static::reportInvalidArgument(\sprintf(
375 $message ?: 'Expected an iterable. Got: %s',
376 static::typeToString($value)
377 ));
378 }
379 }
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 public static function isInstanceOf($value, $class, $message = '')
394 {
395 if (!($value instanceof $class)) {
396 static::reportInvalidArgument(\sprintf(
397 $message ?: 'Expected an instance of %2$s. Got: %s',
398 static::typeToString($value),
399 $class
400 ));
401 }
402 }
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 public static function notInstanceOf($value, $class, $message = '')
417 {
418 if ($value instanceof $class) {
419 static::reportInvalidArgument(\sprintf(
420 $message ?: 'Expected an instance other than %2$s. Got: %s',
421 static::typeToString($value),
422 $class
423 ));
424 }
425 }
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 public static function isInstanceOfAny($value, array $classes, $message = '')
438 {
439 foreach ($classes as $class) {
440 if ($value instanceof $class) {
441 return;
442 }
443 }
444
445 static::reportInvalidArgument(\sprintf(
446 $message ?: 'Expected an instance of any of %2$s. Got: %s',
447 static::typeToString($value),
448 \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 public static function isAOf($value, $class, $message = '')
465 {
466 static::string($class, 'Expected class as a string. Got: %s');
467
468 if (!\is_a($value, $class, \is_string($value))) {
469 static::reportInvalidArgument(sprintf(
470 $message ?: 'Expected an instance of this class or to this class among his parents %2$s. Got: %s',
471 static::typeToString($value),
472 $class
473 ));
474 }
475 }
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 public static function isNotA($value, $class, $message = '')
491 {
492 static::string($class, 'Expected class as a string. Got: %s');
493
494 if (\is_a($value, $class, \is_string($value))) {
495 static::reportInvalidArgument(sprintf(
496 $message ?: 'Expected an instance of this class or to this class among his parents other than %2$s. Got: %s',
497 static::typeToString($value),
498 $class
499 ));
500 }
501 }
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 public static function isAnyOf($value, array $classes, $message = '')
514 {
515 foreach ($classes as $class) {
516 static::string($class, 'Expected class as a string. Got: %s');
517
518 if (\is_a($value, $class, \is_string($value))) {
519 return;
520 }
521 }
522
523 static::reportInvalidArgument(sprintf(
524 $message ?: 'Expected an any of instance of this class or to this class among his parents other than %2$s. Got: %s',
525 static::typeToString($value),
526 \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 public static function isEmpty($value, $message = '')
540 {
541 if (!empty($value)) {
542 static::reportInvalidArgument(\sprintf(
543 $message ?: 'Expected an empty value. Got: %s',
544 static::valueToString($value)
545 ));
546 }
547 }
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 public static function notEmpty($value, $message = '')
559 {
560 if (empty($value)) {
561 static::reportInvalidArgument(\sprintf(
562 $message ?: 'Expected a non-empty value. Got: %s',
563 static::valueToString($value)
564 ));
565 }
566 }
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 public static function null($value, $message = '')
578 {
579 if (null !== $value) {
580 static::reportInvalidArgument(\sprintf(
581 $message ?: 'Expected null. Got: %s',
582 static::valueToString($value)
583 ));
584 }
585 }
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 public static function notNull($value, $message = '')
597 {
598 if (null === $value) {
599 static::reportInvalidArgument(
600 $message ?: 'Expected a value other than null.'
601 );
602 }
603 }
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 public static function true($value, $message = '')
615 {
616 if (true !== $value) {
617 static::reportInvalidArgument(\sprintf(
618 $message ?: 'Expected a value to be true. Got: %s',
619 static::valueToString($value)
620 ));
621 }
622 }
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 public static function false($value, $message = '')
634 {
635 if (false !== $value) {
636 static::reportInvalidArgument(\sprintf(
637 $message ?: 'Expected a value to be false. Got: %s',
638 static::valueToString($value)
639 ));
640 }
641 }
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 public static function notFalse($value, $message = '')
653 {
654 if (false === $value) {
655 static::reportInvalidArgument(
656 $message ?: 'Expected a value other than false.'
657 );
658 }
659 }
660
661 /**
662 * @param mixed $value
663 * @param string $message
664 *
665 * @throws InvalidArgumentException
666 */
667 public static function ip($value, $message = '')
668 {
669 if (false === \filter_var($value, \FILTER_VALIDATE_IP)) {
670 static::reportInvalidArgument(\sprintf(
671 $message ?: 'Expected a value to be an IP. Got: %s',
672 static::valueToString($value)
673 ));
674 }
675 }
676
677 /**
678 * @param mixed $value
679 * @param string $message
680 *
681 * @throws InvalidArgumentException
682 */
683 public static function ipv4($value, $message = '')
684 {
685 if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
686 static::reportInvalidArgument(\sprintf(
687 $message ?: 'Expected a value to be an IPv4. Got: %s',
688 static::valueToString($value)
689 ));
690 }
691 }
692
693 /**
694 * @param mixed $value
695 * @param string $message
696 *
697 * @throws InvalidArgumentException
698 */
699 public static function ipv6($value, $message = '')
700 {
701 if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
702 static::reportInvalidArgument(\sprintf(
703 $message ?: 'Expected a value to be an IPv6. Got: %s',
704 static::valueToString($value)
705 ));
706 }
707 }
708
709 /**
710 * @param mixed $value
711 * @param string $message
712 *
713 * @throws InvalidArgumentException
714 */
715 public static function email($value, $message = '')
716 {
717 if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) {
718 static::reportInvalidArgument(\sprintf(
719 $message ?: 'Expected a value to be a valid e-mail address. Got: %s',
720 static::valueToString($value)
721 ));
722 }
723 }
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 public static function uniqueValues(array $values, $message = '')
734 {
735 $allValues = \count($values);
736 $uniqueValues = \count(\array_unique($values));
737
738 if ($allValues !== $uniqueValues) {
739 $difference = $allValues - $uniqueValues;
740
741 static::reportInvalidArgument(\sprintf(
742 $message ?: 'Expected an array of unique values, but %s of them %s duplicated',
743 $difference,
744 (1 === $difference ? 'is' : 'are')
745 ));
746 }
747 }
748
749 /**
750 * @param mixed $value
751 * @param mixed $expect
752 * @param string $message
753 *
754 * @throws InvalidArgumentException
755 */
756 public static function eq($value, $expect, $message = '')
757 {
758 if ($expect != $value) {
759 static::reportInvalidArgument(\sprintf(
760 $message ?: 'Expected a value equal to %2$s. Got: %s',
761 static::valueToString($value),
762 static::valueToString($expect)
763 ));
764 }
765 }
766
767 /**
768 * @param mixed $value
769 * @param mixed $expect
770 * @param string $message
771 *
772 * @throws InvalidArgumentException
773 */
774 public static function notEq($value, $expect, $message = '')
775 {
776 if ($expect == $value) {
777 static::reportInvalidArgument(\sprintf(
778 $message ?: 'Expected a different value than %s.',
779 static::valueToString($expect)
780 ));
781 }
782 }
783
784 /**
785 * @psalm-pure
786 *
787 * @param mixed $value
788 * @param mixed $expect
789 * @param string $message
790 *
791 * @throws InvalidArgumentException
792 */
793 public static function same($value, $expect, $message = '')
794 {
795 if ($expect !== $value) {
796 static::reportInvalidArgument(\sprintf(
797 $message ?: 'Expected a value identical to %2$s. Got: %s',
798 static::valueToString($value),
799 static::valueToString($expect)
800 ));
801 }
802 }
803
804 /**
805 * @psalm-pure
806 *
807 * @param mixed $value
808 * @param mixed $expect
809 * @param string $message
810 *
811 * @throws InvalidArgumentException
812 */
813 public static function notSame($value, $expect, $message = '')
814 {
815 if ($expect === $value) {
816 static::reportInvalidArgument(\sprintf(
817 $message ?: 'Expected a value not identical to %s.',
818 static::valueToString($expect)
819 ));
820 }
821 }
822
823 /**
824 * @psalm-pure
825 *
826 * @param mixed $value
827 * @param mixed $limit
828 * @param string $message
829 *
830 * @throws InvalidArgumentException
831 */
832 public static function greaterThan($value, $limit, $message = '')
833 {
834 if ($value <= $limit) {
835 static::reportInvalidArgument(\sprintf(
836 $message ?: 'Expected a value greater than %2$s. Got: %s',
837 static::valueToString($value),
838 static::valueToString($limit)
839 ));
840 }
841 }
842
843 /**
844 * @psalm-pure
845 *
846 * @param mixed $value
847 * @param mixed $limit
848 * @param string $message
849 *
850 * @throws InvalidArgumentException
851 */
852 public static function greaterThanEq($value, $limit, $message = '')
853 {
854 if ($value < $limit) {
855 static::reportInvalidArgument(\sprintf(
856 $message ?: 'Expected a value greater than or equal to %2$s. Got: %s',
857 static::valueToString($value),
858 static::valueToString($limit)
859 ));
860 }
861 }
862
863 /**
864 * @psalm-pure
865 *
866 * @param mixed $value
867 * @param mixed $limit
868 * @param string $message
869 *
870 * @throws InvalidArgumentException
871 */
872 public static function lessThan($value, $limit, $message = '')
873 {
874 if ($value >= $limit) {
875 static::reportInvalidArgument(\sprintf(
876 $message ?: 'Expected a value less than %2$s. Got: %s',
877 static::valueToString($value),
878 static::valueToString($limit)
879 ));
880 }
881 }
882
883 /**
884 * @psalm-pure
885 *
886 * @param mixed $value
887 * @param mixed $limit
888 * @param string $message
889 *
890 * @throws InvalidArgumentException
891 */
892 public static function lessThanEq($value, $limit, $message = '')
893 {
894 if ($value > $limit) {
895 static::reportInvalidArgument(\sprintf(
896 $message ?: 'Expected a value less than or equal to %2$s. Got: %s',
897 static::valueToString($value),
898 static::valueToString($limit)
899 ));
900 }
901 }
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 public static function range($value, $min, $max, $message = '')
916 {
917 if ($value < $min || $value > $max) {
918 static::reportInvalidArgument(\sprintf(
919 $message ?: 'Expected a value between %2$s and %3$s. Got: %s',
920 static::valueToString($value),
921 static::valueToString($min),
922 static::valueToString($max)
923 ));
924 }
925 }
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 public static function oneOf($value, array $values, $message = '')
939 {
940 static::inArray($value, $values, $message);
941 }
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 public static function inArray($value, array $values, $message = '')
955 {
956 if (!\in_array($value, $values, true)) {
957 static::reportInvalidArgument(\sprintf(
958 $message ?: 'Expected one of: %2$s. Got: %s',
959 static::valueToString($value),
960 \implode(', ', \array_map(array('static', 'valueToString'), $values))
961 ));
962 }
963 }
964
965 /**
966 * @psalm-pure
967 *
968 * @param string $value
969 * @param string $subString
970 * @param string $message
971 *
972 * @throws InvalidArgumentException
973 */
974 public static function contains($value, $subString, $message = '')
975 {
976 if (false === \strpos($value, $subString)) {
977 static::reportInvalidArgument(\sprintf(
978 $message ?: 'Expected a value to contain %2$s. Got: %s',
979 static::valueToString($value),
980 static::valueToString($subString)
981 ));
982 }
983 }
984
985 /**
986 * @psalm-pure
987 *
988 * @param string $value
989 * @param string $subString
990 * @param string $message
991 *
992 * @throws InvalidArgumentException
993 */
994 public static function notContains($value, $subString, $message = '')
995 {
996 if (false !== \strpos($value, $subString)) {
997 static::reportInvalidArgument(\sprintf(
998 $message ?: '%2$s was not expected to be contained in a value. Got: %s',
999 static::valueToString($value),
1000 static::valueToString($subString)
1001 ));
1002 }
1003 }
1004
1005 /**
1006 * @psalm-pure
1007 *
1008 * @param string $value
1009 * @param string $message
1010 *
1011 * @throws InvalidArgumentException
1012 */
1013 public static function notWhitespaceOnly($value, $message = '')
1014 {
1015 if (\preg_match('/^\s*$/', $value)) {
1016 static::reportInvalidArgument(\sprintf(
1017 $message ?: 'Expected a non-whitespace string. Got: %s',
1018 static::valueToString($value)
1019 ));
1020 }
1021 }
1022
1023 /**
1024 * @psalm-pure
1025 *
1026 * @param string $value
1027 * @param string $prefix
1028 * @param string $message
1029 *
1030 * @throws InvalidArgumentException
1031 */
1032 public static function startsWith($value, $prefix, $message = '')
1033 {
1034 if (0 !== \strpos($value, $prefix)) {
1035 static::reportInvalidArgument(\sprintf(
1036 $message ?: 'Expected a value to start with %2$s. Got: %s',
1037 static::valueToString($value),
1038 static::valueToString($prefix)
1039 ));
1040 }
1041 }
1042
1043 /**
1044 * @psalm-pure
1045 *
1046 * @param string $value
1047 * @param string $prefix
1048 * @param string $message
1049 *
1050 * @throws InvalidArgumentException
1051 */
1052 public static function notStartsWith($value, $prefix, $message = '')
1053 {
1054 if (0 === \strpos($value, $prefix)) {
1055 static::reportInvalidArgument(\sprintf(
1056 $message ?: 'Expected a value not to start with %2$s. Got: %s',
1057 static::valueToString($value),
1058 static::valueToString($prefix)
1059 ));
1060 }
1061 }
1062
1063 /**
1064 * @psalm-pure
1065 *
1066 * @param mixed $value
1067 * @param string $message
1068 *
1069 * @throws InvalidArgumentException
1070 */
1071 public static function startsWithLetter($value, $message = '')
1072 {
1073 static::string($value);
1074
1075 $valid = isset($value[0]);
1076
1077 if ($valid) {
1078 $locale = \setlocale(LC_CTYPE, 0);
1079 \setlocale(LC_CTYPE, 'C');
1080 $valid = \ctype_alpha($value[0]);
1081 \setlocale(LC_CTYPE, $locale);
1082 }
1083
1084 if (!$valid) {
1085 static::reportInvalidArgument(\sprintf(
1086 $message ?: 'Expected a value to start with a letter. Got: %s',
1087 static::valueToString($value)
1088 ));
1089 }
1090 }
1091
1092 /**
1093 * @psalm-pure
1094 *
1095 * @param string $value
1096 * @param string $suffix
1097 * @param string $message
1098 *
1099 * @throws InvalidArgumentException
1100 */
1101 public static function endsWith($value, $suffix, $message = '')
1102 {
1103 if ($suffix !== \substr($value, -\strlen($suffix))) {
1104 static::reportInvalidArgument(\sprintf(
1105 $message ?: 'Expected a value to end with %2$s. Got: %s',
1106 static::valueToString($value),
1107 static::valueToString($suffix)
1108 ));
1109 }
1110 }
1111
1112 /**
1113 * @psalm-pure
1114 *
1115 * @param string $value
1116 * @param string $suffix
1117 * @param string $message
1118 *
1119 * @throws InvalidArgumentException
1120 */
1121 public static function notEndsWith($value, $suffix, $message = '')
1122 {
1123 if ($suffix === \substr($value, -\strlen($suffix))) {
1124 static::reportInvalidArgument(\sprintf(
1125 $message ?: 'Expected a value not to end with %2$s. Got: %s',
1126 static::valueToString($value),
1127 static::valueToString($suffix)
1128 ));
1129 }
1130 }
1131
1132 /**
1133 * @psalm-pure
1134 *
1135 * @param string $value
1136 * @param string $pattern
1137 * @param string $message
1138 *
1139 * @throws InvalidArgumentException
1140 */
1141 public static function regex($value, $pattern, $message = '')
1142 {
1143 if (!\preg_match($pattern, $value)) {
1144 static::reportInvalidArgument(\sprintf(
1145 $message ?: 'The value %s does not match the expected pattern.',
1146 static::valueToString($value)
1147 ));
1148 }
1149 }
1150
1151 /**
1152 * @psalm-pure
1153 *
1154 * @param string $value
1155 * @param string $pattern
1156 * @param string $message
1157 *
1158 * @throws InvalidArgumentException
1159 */
1160 public static function notRegex($value, $pattern, $message = '')
1161 {
1162 if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
1163 static::reportInvalidArgument(\sprintf(
1164 $message ?: 'The value %s matches the pattern %s (at offset %d).',
1165 static::valueToString($value),
1166 static::valueToString($pattern),
1167 $matches[0][1]
1168 ));
1169 }
1170 }
1171
1172 /**
1173 * @psalm-pure
1174 *
1175 * @param mixed $value
1176 * @param string $message
1177 *
1178 * @throws InvalidArgumentException
1179 */
1180 public static function unicodeLetters($value, $message = '')
1181 {
1182 static::string($value);
1183
1184 if (!\preg_match('/^\p{L}+$/u', $value)) {
1185 static::reportInvalidArgument(\sprintf(
1186 $message ?: 'Expected a value to contain only Unicode letters. Got: %s',
1187 static::valueToString($value)
1188 ));
1189 }
1190 }
1191
1192 /**
1193 * @psalm-pure
1194 *
1195 * @param mixed $value
1196 * @param string $message
1197 *
1198 * @throws InvalidArgumentException
1199 */
1200 public static function alpha($value, $message = '')
1201 {
1202 static::string($value);
1203
1204 $locale = \setlocale(LC_CTYPE, 0);
1205 \setlocale(LC_CTYPE, 'C');
1206 $valid = !\ctype_alpha($value);
1207 \setlocale(LC_CTYPE, $locale);
1208
1209 if ($valid) {
1210 static::reportInvalidArgument(\sprintf(
1211 $message ?: 'Expected a value to contain only letters. Got: %s',
1212 static::valueToString($value)
1213 ));
1214 }
1215 }
1216
1217 /**
1218 * @psalm-pure
1219 *
1220 * @param string $value
1221 * @param string $message
1222 *
1223 * @throws InvalidArgumentException
1224 */
1225 public static function digits($value, $message = '')
1226 {
1227 $locale = \setlocale(LC_CTYPE, 0);
1228 \setlocale(LC_CTYPE, 'C');
1229 $valid = !\ctype_digit($value);
1230 \setlocale(LC_CTYPE, $locale);
1231
1232 if ($valid) {
1233 static::reportInvalidArgument(\sprintf(
1234 $message ?: 'Expected a value to contain digits only. Got: %s',
1235 static::valueToString($value)
1236 ));
1237 }
1238 }
1239
1240 /**
1241 * @psalm-pure
1242 *
1243 * @param string $value
1244 * @param string $message
1245 *
1246 * @throws InvalidArgumentException
1247 */
1248 public static function alnum($value, $message = '')
1249 {
1250 $locale = \setlocale(LC_CTYPE, 0);
1251 \setlocale(LC_CTYPE, 'C');
1252 $valid = !\ctype_alnum($value);
1253 \setlocale(LC_CTYPE, $locale);
1254
1255 if ($valid) {
1256 static::reportInvalidArgument(\sprintf(
1257 $message ?: 'Expected a value to contain letters and digits only. Got: %s',
1258 static::valueToString($value)
1259 ));
1260 }
1261 }
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 public static function lower($value, $message = '')
1273 {
1274 $locale = \setlocale(LC_CTYPE, 0);
1275 \setlocale(LC_CTYPE, 'C');
1276 $valid = !\ctype_lower($value);
1277 \setlocale(LC_CTYPE, $locale);
1278
1279 if ($valid) {
1280 static::reportInvalidArgument(\sprintf(
1281 $message ?: 'Expected a value to contain lowercase characters only. Got: %s',
1282 static::valueToString($value)
1283 ));
1284 }
1285 }
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 public static function upper($value, $message = '')
1297 {
1298 $locale = \setlocale(LC_CTYPE, 0);
1299 \setlocale(LC_CTYPE, 'C');
1300 $valid = !\ctype_upper($value);
1301 \setlocale(LC_CTYPE, $locale);
1302
1303 if ($valid) {
1304 static::reportInvalidArgument(\sprintf(
1305 $message ?: 'Expected a value to contain uppercase characters only. Got: %s',
1306 static::valueToString($value)
1307 ));
1308 }
1309 }
1310
1311 /**
1312 * @psalm-pure
1313 *
1314 * @param string $value
1315 * @param int $length
1316 * @param string $message
1317 *
1318 * @throws InvalidArgumentException
1319 */
1320 public static function length($value, $length, $message = '')
1321 {
1322 if ($length !== static::strlen($value)) {
1323 static::reportInvalidArgument(\sprintf(
1324 $message ?: 'Expected a value to contain %2$s characters. Got: %s',
1325 static::valueToString($value),
1326 $length
1327 ));
1328 }
1329 }
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 public static function minLength($value, $min, $message = '')
1343 {
1344 if (static::strlen($value) < $min) {
1345 static::reportInvalidArgument(\sprintf(
1346 $message ?: 'Expected a value to contain at least %2$s characters. Got: %s',
1347 static::valueToString($value),
1348 $min
1349 ));
1350 }
1351 }
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 public static function maxLength($value, $max, $message = '')
1365 {
1366 if (static::strlen($value) > $max) {
1367 static::reportInvalidArgument(\sprintf(
1368 $message ?: 'Expected a value to contain at most %2$s characters. Got: %s',
1369 static::valueToString($value),
1370 $max
1371 ));
1372 }
1373 }
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 public static function lengthBetween($value, $min, $max, $message = '')
1388 {
1389 $length = static::strlen($value);
1390
1391 if ($length < $min || $length > $max) {
1392 static::reportInvalidArgument(\sprintf(
1393 $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s',
1394 static::valueToString($value),
1395 $min,
1396 $max
1397 ));
1398 }
1399 }
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 public static function fileExists($value, $message = '')
1410 {
1411 static::string($value);
1412
1413 if (!\file_exists($value)) {
1414 static::reportInvalidArgument(\sprintf(
1415 $message ?: 'The file %s does not exist.',
1416 static::valueToString($value)
1417 ));
1418 }
1419 }
1420
1421 /**
1422 * @param mixed $value
1423 * @param string $message
1424 *
1425 * @throws InvalidArgumentException
1426 */
1427 public static function file($value, $message = '')
1428 {
1429 static::fileExists($value, $message);
1430
1431 if (!\is_file($value)) {
1432 static::reportInvalidArgument(\sprintf(
1433 $message ?: 'The path %s is not a file.',
1434 static::valueToString($value)
1435 ));
1436 }
1437 }
1438
1439 /**
1440 * @param mixed $value
1441 * @param string $message
1442 *
1443 * @throws InvalidArgumentException
1444 */
1445 public static function directory($value, $message = '')
1446 {
1447 static::fileExists($value, $message);
1448
1449 if (!\is_dir($value)) {
1450 static::reportInvalidArgument(\sprintf(
1451 $message ?: 'The path %s is no directory.',
1452 static::valueToString($value)
1453 ));
1454 }
1455 }
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 public static function classExists($value, $message = '')
1498 {
1499 if (!\class_exists($value)) {
1500 static::reportInvalidArgument(\sprintf(
1501 $message ?: 'Expected an existing class name. Got: %s',
1502 static::valueToString($value)
1503 ));
1504 }
1505 }
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 public static function subclassOf($value, $class, $message = '')
1520 {
1521 if (!\is_subclass_of($value, $class)) {
1522 static::reportInvalidArgument(\sprintf(
1523 $message ?: 'Expected a sub-class of %2$s. Got: %s',
1524 static::valueToString($value),
1525 static::valueToString($class)
1526 ));
1527 }
1528 }
1529
1530 /**
1531 * @psalm-assert class-string $value
1532 *
1533 * @param mixed $value
1534 * @param string $message
1535 *
1536 * @throws InvalidArgumentException
1537 */
1538 public static function interfaceExists($value, $message = '')
1539 {
1540 if (!\interface_exists($value)) {
1541 static::reportInvalidArgument(\sprintf(
1542 $message ?: 'Expected an existing interface name. got %s',
1543 static::valueToString($value)
1544 ));
1545 }
1546 }
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 public static function implementsInterface($value, $interface, $message = '')
1561 {
1562 if (!\in_array($interface, \class_implements($value))) {
1563 static::reportInvalidArgument(\sprintf(
1564 $message ?: 'Expected an implementation of %2$s. Got: %s',
1565 static::valueToString($value),
1566 static::valueToString($interface)
1567 ));
1568 }
1569 }
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 public static function propertyExists($classOrObject, $property, $message = '')
1582 {
1583 if (!\property_exists($classOrObject, $property)) {
1584 static::reportInvalidArgument(\sprintf(
1585 $message ?: 'Expected the property %s to exist.',
1586 static::valueToString($property)
1587 ));
1588 }
1589 }
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 public static function propertyNotExists($classOrObject, $property, $message = '')
1602 {
1603 if (\property_exists($classOrObject, $property)) {
1604 static::reportInvalidArgument(\sprintf(
1605 $message ?: 'Expected the property %s to not exist.',
1606 static::valueToString($property)
1607 ));
1608 }
1609 }
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 public static function methodExists($classOrObject, $method, $message = '')
1622 {
1623 if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) {
1624 static::reportInvalidArgument(\sprintf(
1625 $message ?: 'Expected the method %s to exist.',
1626 static::valueToString($method)
1627 ));
1628 }
1629 }
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 public static function methodNotExists($classOrObject, $method, $message = '')
1642 {
1643 if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) {
1644 static::reportInvalidArgument(\sprintf(
1645 $message ?: 'Expected the method %s to not exist.',
1646 static::valueToString($method)
1647 ));
1648 }
1649 }
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 public static function keyExists($array, $key, $message = '')
1661 {
1662 if (!(isset($array[$key]) || \array_key_exists($key, $array))) {
1663 static::reportInvalidArgument(\sprintf(
1664 $message ?: 'Expected the key %s to exist.',
1665 static::valueToString($key)
1666 ));
1667 }
1668 }
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 public static function keyNotExists($array, $key, $message = '')
1680 {
1681 if (isset($array[$key]) || \array_key_exists($key, $array)) {
1682 static::reportInvalidArgument(\sprintf(
1683 $message ?: 'Expected the key %s to not exist.',
1684 static::valueToString($key)
1685 ));
1686 }
1687 }
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 public static function validArrayKey($value, $message = '')
1701 {
1702 if (!(\is_int($value) || \is_string($value))) {
1703 static::reportInvalidArgument(\sprintf(
1704 $message ?: 'Expected string or integer. Got: %s',
1705 static::typeToString($value)
1706 ));
1707 }
1708 }
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 public static function count($array, $number, $message = '')
1720 {
1721 static::eq(
1722 \count($array),
1723 $number,
1724 \sprintf(
1725 $message ?: 'Expected an array to contain %d elements. Got: %d.',
1726 $number,
1727 \count($array)
1728 )
1729 );
1730 }
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 public static function minCount($array, $min, $message = '')
1742 {
1743 if (\count($array) < $min) {
1744 static::reportInvalidArgument(\sprintf(
1745 $message ?: 'Expected an array to contain at least %2$d elements. Got: %d',
1746 \count($array),
1747 $min
1748 ));
1749 }
1750 }
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 public static function maxCount($array, $max, $message = '')
1762 {
1763 if (\count($array) > $max) {
1764 static::reportInvalidArgument(\sprintf(
1765 $message ?: 'Expected an array to contain at most %2$d elements. Got: %d',
1766 \count($array),
1767 $max
1768 ));
1769 }
1770 }
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 public static function countBetween($array, $min, $max, $message = '')
1783 {
1784 $count = \count($array);
1785
1786 if ($count < $min || $count > $max) {
1787 static::reportInvalidArgument(\sprintf(
1788 $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d',
1789 $count,
1790 $min,
1791 $max
1792 ));
1793 }
1794 }
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 public static function isList($array, $message = '')
1806 {
1807 if (!\is_array($array) || $array !== \array_values($array)) {
1808 static::reportInvalidArgument(
1809 $message ?: 'Expected list - non-associative array.'
1810 );
1811 }
1812 }
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 public static function isNonEmptyList($array, $message = '')
1824 {
1825 static::isList($array, $message);
1826 static::notEmpty($array, $message);
1827 }
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 public static function isMap($array, $message = '')
1841 {
1842 if (
1843 !\is_array($array) ||
1844 \array_keys($array) !== \array_filter(\array_keys($array), '\is_string')
1845 ) {
1846 static::reportInvalidArgument(
1847 $message ?: 'Expected map - associative array with string keys.'
1848 );
1849 }
1850 }
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 public static function isNonEmptyMap($array, $message = '')
1865 {
1866 static::isMap($array, $message);
1867 static::notEmpty($array, $message);
1868 }
1869
1870 /**
1871 * @psalm-pure
1872 *
1873 * @param string $value
1874 * @param string $message
1875 *
1876 * @throws InvalidArgumentException
1877 */
1878 public static function uuid($value, $message = '')
1879 {
1880 $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 if ('00000000-0000-0000-0000-000000000000' === $value) {
1885 return;
1886 }
1887
1888 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 static::reportInvalidArgument(\sprintf(
1890 $message ?: 'Value %s is not a valid UUID.',
1891 static::valueToString($value)
1892 ));
1893 }
1894 }
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 public static function throws(Closure $expression, $class = 'Exception', $message = '')
1906 {
1907 static::string($class);
1908
1909 $actual = 'none';
1910
1911 try {
1912 $expression();
1913 } catch (Exception $e) {
1914 $actual = \get_class($e);
1915 if ($e instanceof $class) {
1916 return;
1917 }
1918 } catch (Throwable $e) {
1919 $actual = \get_class($e);
1920 if ($e instanceof $class) {
1921 return;
1922 }
1923 }
1924
1925 static::reportInvalidArgument($message ?: \sprintf(
1926 'Expected to throw "%s", got "%s"',
1927 $class,
1928 $actual
1929 ));
1930 }
1931
1932 /**
1933 * @throws BadMethodCallException
1934 */
1935 public static function __callStatic($name, $arguments)
1936 {
1937 if ('nullOr' === \substr($name, 0, 6)) {
1938 if (null !== $arguments[0]) {
1939 $method = \lcfirst(\substr($name, 6));
1940 \call_user_func_array(array('static', $method), $arguments);
1941 }
1942
1943 return;
1944 }
1945
1946 if ('all' === \substr($name, 0, 3)) {
1947 static::isIterable($arguments[0]);
1948
1949 $method = \lcfirst(\substr($name, 3));
1950 $args = $arguments;
1951
1952 foreach ($arguments[0] as $entry) {
1953 $args[0] = $entry;
1954
1955 \call_user_func_array(array('static', $method), $args);
1956 }
1957
1958 return;
1959 }
1960
1961 throw new BadMethodCallException('No such method: '.$name);
1962 }
1963
1964 /**
1965 * @param mixed $value
1966 *
1967 * @return string
1968 */
1969 protected static function valueToString($value)
1970 {
1971 if (null === $value) {
1972 return 'null';
1973 }
1974
1975 if (true === $value) {
1976 return 'true';
1977 }
1978
1979 if (false === $value) {
1980 return 'false';
1981 }
1982
1983 if (\is_array($value)) {
1984 return 'array';
1985 }
1986
1987 if (\is_object($value)) {
1988 if (\method_exists($value, '__toString')) {
1989 return \get_class($value).': '.self::valueToString($value->__toString());
1990 }
1991
1992 if ($value instanceof DateTime || $value instanceof DateTimeImmutable) {
1993 return \get_class($value).': '.self::valueToString($value->format('c'));
1994 }
1995
1996 return \get_class($value);
1997 }
1998
1999 if (\is_resource($value)) {
2000 return 'resource';
2001 }
2002
2003 if (\is_string($value)) {
2004 return '"'.$value.'"';
2005 }
2006
2007 return (string) $value;
2008 }
2009
2010 /**
2011 * @param mixed $value
2012 *
2013 * @return string
2014 */
2015 protected static function typeToString($value)
2016 {
2017 return \is_object($value) ? \get_class($value) : \gettype($value);
2018 }
2019
2020 protected static function strlen($value)
2021 {
2022 if (!\function_exists('mb_detect_encoding')) {
2023 return \strlen($value);
2024 }
2025
2026 if (false === $encoding = \mb_detect_encoding($value)) {
2027 return \strlen($value);
2028 }
2029
2030 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 protected static function reportInvalidArgument($message)
2041 {
2042 throw new InvalidArgumentException($message);
2043 }
2044
2045 private function __construct()
2046 {
2047 }
2048}