Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  
   3  /**
   4   * Assert
   5   *
   6   * LICENSE
   7   *
   8   * This source file is subject to the MIT license that is bundled
   9   * with this package in the file LICENSE.txt.
  10   * If you did not receive a copy of the license and are unable to
  11   * obtain it through the world-wide-web, please send an email
  12   * to kontakt@beberlei.de so I can send you a copy immediately.
  13   */
  14  
  15  namespace Assert;
  16  
  17  use ArrayAccess;
  18  use BadMethodCallException;
  19  use Countable;
  20  use DateTime;
  21  use ReflectionClass;
  22  use ReflectionException;
  23  use ResourceBundle;
  24  use SimpleXMLElement;
  25  use Throwable;
  26  use Traversable;
  27  
  28  /**
  29   * Assert library.
  30   *
  31   * @author Benjamin Eberlei <kontakt@beberlei.de>
  32   *
  33   * @method static bool allAlnum(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric for all values.
  34   * @method static bool allBase64(string $value, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined for all values.
  35   * @method static bool allBetween(mixed $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit for all values.
  36   * @method static bool allBetweenExclusive(mixed $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit for all values.
  37   * @method static bool allBetweenLength(mixed $value, int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths for all values.
  38   * @method static bool allBoolean(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is php boolean for all values.
  39   * @method static bool allChoice(mixed $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices for all values.
  40   * @method static bool allChoicesNotEmpty(array $values, array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content for all values.
  41   * @method static bool allClassExists(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that the class exists for all values.
  42   * @method static bool allContains(mixed $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars for all values.
  43   * @method static bool allCount(array|Countable|ResourceBundle|SimpleXMLElement $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count for all values.
  44   * @method static bool allDate(string $value, string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format for all values.
  45   * @method static bool allDefined(mixed $constant, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined for all values.
  46   * @method static bool allDigit(mixed $value, string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit for all values.
  47   * @method static bool allDirectory(string $value, string|callable $message = null, string $propertyPath = null) Assert that a directory exists for all values.
  48   * @method static bool allE164(string $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number for all values.
  49   * @method static bool allEmail(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL) for all values.
  50   * @method static bool allEndsWith(mixed $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars for all values.
  51   * @method static bool allEq(mixed $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==) for all values.
  52   * @method static bool allEqArraySubset(mixed $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset for all values.
  53   * @method static bool allExtensionLoaded(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded for all values.
  54   * @method static bool allExtensionVersion(string $extension, string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed for all values.
  55   * @method static bool allFalse(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False for all values.
  56   * @method static bool allFile(string $value, string|callable $message = null, string $propertyPath = null) Assert that a file exists for all values.
  57   * @method static bool allFloat(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php float for all values.
  58   * @method static bool allGreaterOrEqualThan(mixed $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit for all values.
  59   * @method static bool allGreaterThan(mixed $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit for all values.
  60   * @method static bool allImplementsInterface(mixed $class, string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface for all values.
  61   * @method static bool allInArray(mixed $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice() for all values.
  62   * @method static bool allInteger(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer for all values.
  63   * @method static bool allIntegerish(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish for all values.
  64   * @method static bool allInterfaceExists(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that the interface exists for all values.
  65   * @method static bool allIp(string $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address for all values.
  66   * @method static bool allIpv4(string $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address for all values.
  67   * @method static bool allIpv6(string $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address for all values.
  68   * @method static bool allIsArray(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array for all values.
  69   * @method static bool allIsArrayAccessible(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object for all values.
  70   * @method static bool allIsCallable(mixed $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable for all values.
  71   * @method static bool allIsCountable(array|Countable|ResourceBundle|SimpleXMLElement $value, string|callable $message = null, string $propertyPath = null) Assert that value is countable for all values.
  72   * @method static bool allIsInstanceOf(mixed $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name for all values.
  73   * @method static bool allIsJsonString(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string for all values.
  74   * @method static bool allIsObject(mixed $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object for all values.
  75   * @method static bool allIsResource(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is a resource for all values.
  76   * @method static bool allIsTraversable(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object for all values.
  77   * @method static bool allKeyExists(mixed $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array for all values.
  78   * @method static bool allKeyIsset(mixed $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset() for all values.
  79   * @method static bool allKeyNotExists(mixed $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array for all values.
  80   * @method static bool allLength(mixed $value, int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length for all values.
  81   * @method static bool allLessOrEqualThan(mixed $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit for all values.
  82   * @method static bool allLessThan(mixed $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit for all values.
  83   * @method static bool allMax(mixed $value, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit for all values.
  84   * @method static bool allMaxCount(array|Countable|ResourceBundle|SimpleXMLElement $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements for all values.
  85   * @method static bool allMaxLength(mixed $value, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars for all values.
  86   * @method static bool allMethodExists(string $value, mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object for all values.
  87   * @method static bool allMin(mixed $value, mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit for all values.
  88   * @method static bool allMinCount(array|Countable|ResourceBundle|SimpleXMLElement $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements for all values.
  89   * @method static bool allMinLength(mixed $value, int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long for all values.
  90   * @method static bool allNoContent(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is empty for all values.
  91   * @method static bool allNotBlank(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is not blank for all values.
  92   * @method static bool allNotContains(mixed $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars for all values.
  93   * @method static bool allNotEmpty(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is not empty for all values.
  94   * @method static bool allNotEmptyKey(mixed $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty for all values.
  95   * @method static bool allNotEq(mixed $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==) for all values.
  96   * @method static bool allNotInArray(mixed $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices for all values.
  97   * @method static bool allNotIsInstanceOf(mixed $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name for all values.
  98   * @method static bool allNotNull(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is not null for all values.
  99   * @method static bool allNotRegex(mixed $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex for all values.
 100   * @method static bool allNotSame(mixed $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===) for all values.
 101   * @method static bool allNull(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is null for all values.
 102   * @method static bool allNumeric(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is numeric for all values.
 103   * @method static bool allObjectOrClass(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists for all values.
 104   * @method static bool allPhpVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version for all values.
 105   * @method static bool allPropertiesExist(mixed $value, array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist for all values.
 106   * @method static bool allPropertyExists(mixed $value, string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists for all values.
 107   * @method static bool allRange(mixed $value, mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers for all values.
 108   * @method static bool allReadable(string $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something readable for all values.
 109   * @method static bool allRegex(mixed $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex for all values.
 110   * @method static bool allSame(mixed $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===) for all values.
 111   * @method static bool allSatisfy(mixed $value, callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback for all values.
 112   * @method static bool allScalar(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar for all values.
 113   * @method static bool allStartsWith(mixed $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars for all values.
 114   * @method static bool allString(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is a string for all values.
 115   * @method static bool allSubclassOf(mixed $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name for all values.
 116   * @method static bool allTrue(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True for all values.
 117   * @method static bool allUrl(mixed $value, string|callable $message = null, string $propertyPath = null) Assert that value is an URL for all values.
 118   * @method static bool allUuid(string $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID for all values.
 119   * @method static bool allVersion(string $version1, string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions for all values.
 120   * @method static bool allWriteable(string $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable for all values.
 121   * @method static bool nullOrAlnum(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric or that the value is null.
 122   * @method static bool nullOrBase64(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined or that the value is null.
 123   * @method static bool nullOrBetween(mixed|null $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit or that the value is null.
 124   * @method static bool nullOrBetweenExclusive(mixed|null $value, mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit or that the value is null.
 125   * @method static bool nullOrBetweenLength(mixed|null $value, int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths or that the value is null.
 126   * @method static bool nullOrBoolean(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is php boolean or that the value is null.
 127   * @method static bool nullOrChoice(mixed|null $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices or that the value is null.
 128   * @method static bool nullOrChoicesNotEmpty(array|null $values, array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content or that the value is null.
 129   * @method static bool nullOrClassExists(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the class exists or that the value is null.
 130   * @method static bool nullOrContains(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars or that the value is null.
 131   * @method static bool nullOrCount(array|Countable|ResourceBundle|SimpleXMLElement|null $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count or that the value is null.
 132   * @method static bool nullOrDate(string|null $value, string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format or that the value is null.
 133   * @method static bool nullOrDefined(mixed|null $constant, string|callable $message = null, string $propertyPath = null) Assert that a constant is defined or that the value is null.
 134   * @method static bool nullOrDigit(mixed|null $value, string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit or that the value is null.
 135   * @method static bool nullOrDirectory(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that a directory exists or that the value is null.
 136   * @method static bool nullOrE164(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number or that the value is null.
 137   * @method static bool nullOrEmail(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL) or that the value is null.
 138   * @method static bool nullOrEndsWith(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars or that the value is null.
 139   * @method static bool nullOrEq(mixed|null $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==) or that the value is null.
 140   * @method static bool nullOrEqArraySubset(mixed|null $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset or that the value is null.
 141   * @method static bool nullOrExtensionLoaded(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded or that the value is null.
 142   * @method static bool nullOrExtensionVersion(string|null $extension, string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed or that the value is null.
 143   * @method static bool nullOrFalse(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False or that the value is null.
 144   * @method static bool nullOrFile(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that a file exists or that the value is null.
 145   * @method static bool nullOrFloat(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php float or that the value is null.
 146   * @method static bool nullOrGreaterOrEqualThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit or that the value is null.
 147   * @method static bool nullOrGreaterThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit or that the value is null.
 148   * @method static bool nullOrImplementsInterface(mixed|null $class, string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface or that the value is null.
 149   * @method static bool nullOrInArray(mixed|null $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice() or that the value is null.
 150   * @method static bool nullOrInteger(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer or that the value is null.
 151   * @method static bool nullOrIntegerish(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish or that the value is null.
 152   * @method static bool nullOrInterfaceExists(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the interface exists or that the value is null.
 153   * @method static bool nullOrIp(string|null $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address or that the value is null.
 154   * @method static bool nullOrIpv4(string|null $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address or that the value is null.
 155   * @method static bool nullOrIpv6(string|null $value, int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address or that the value is null.
 156   * @method static bool nullOrIsArray(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or that the value is null.
 157   * @method static bool nullOrIsArrayAccessible(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object or that the value is null.
 158   * @method static bool nullOrIsCallable(mixed|null $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable or that the value is null.
 159   * @method static bool nullOrIsCountable(array|Countable|ResourceBundle|SimpleXMLElement|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is countable or that the value is null.
 160   * @method static bool nullOrIsInstanceOf(mixed|null $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name or that the value is null.
 161   * @method static bool nullOrIsJsonString(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string or that the value is null.
 162   * @method static bool nullOrIsObject(mixed|null $value, string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object or that the value is null.
 163   * @method static bool nullOrIsResource(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a resource or that the value is null.
 164   * @method static bool nullOrIsTraversable(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object or that the value is null.
 165   * @method static bool nullOrKeyExists(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array or that the value is null.
 166   * @method static bool nullOrKeyIsset(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset() or that the value is null.
 167   * @method static bool nullOrKeyNotExists(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array or that the value is null.
 168   * @method static bool nullOrLength(mixed|null $value, int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length or that the value is null.
 169   * @method static bool nullOrLessOrEqualThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit or that the value is null.
 170   * @method static bool nullOrLessThan(mixed|null $value, mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit or that the value is null.
 171   * @method static bool nullOrMax(mixed|null $value, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit or that the value is null.
 172   * @method static bool nullOrMaxCount(array|Countable|ResourceBundle|SimpleXMLElement|null $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements or that the value is null.
 173   * @method static bool nullOrMaxLength(mixed|null $value, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars or that the value is null.
 174   * @method static bool nullOrMethodExists(string|null $value, mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object or that the value is null.
 175   * @method static bool nullOrMin(mixed|null $value, mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit or that the value is null.
 176   * @method static bool nullOrMinCount(array|Countable|ResourceBundle|SimpleXMLElement|null $countable, int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements or that the value is null.
 177   * @method static bool nullOrMinLength(mixed|null $value, int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long or that the value is null.
 178   * @method static bool nullOrNoContent(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is empty or that the value is null.
 179   * @method static bool nullOrNotBlank(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is not blank or that the value is null.
 180   * @method static bool nullOrNotContains(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars or that the value is null.
 181   * @method static bool nullOrNotEmpty(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is not empty or that the value is null.
 182   * @method static bool nullOrNotEmptyKey(mixed|null $value, string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty or that the value is null.
 183   * @method static bool nullOrNotEq(mixed|null $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==) or that the value is null.
 184   * @method static bool nullOrNotInArray(mixed|null $value, array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices or that the value is null.
 185   * @method static bool nullOrNotIsInstanceOf(mixed|null $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name or that the value is null.
 186   * @method static bool nullOrNotNull(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is not null or that the value is null.
 187   * @method static bool nullOrNotRegex(mixed|null $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex or that the value is null.
 188   * @method static bool nullOrNotSame(mixed|null $value1, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===) or that the value is null.
 189   * @method static bool nullOrNull(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is null or that the value is null.
 190   * @method static bool nullOrNumeric(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is numeric or that the value is null.
 191   * @method static bool nullOrObjectOrClass(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists or that the value is null.
 192   * @method static bool nullOrPhpVersion(string|null $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version or that the value is null.
 193   * @method static bool nullOrPropertiesExist(mixed|null $value, array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist or that the value is null.
 194   * @method static bool nullOrPropertyExists(mixed|null $value, string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists or that the value is null.
 195   * @method static bool nullOrRange(mixed|null $value, mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers or that the value is null.
 196   * @method static bool nullOrReadable(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something readable or that the value is null.
 197   * @method static bool nullOrRegex(mixed|null $value, string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex or that the value is null.
 198   * @method static bool nullOrSame(mixed|null $value, mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===) or that the value is null.
 199   * @method static bool nullOrSatisfy(mixed|null $value, callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback or that the value is null.
 200   * @method static bool nullOrScalar(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar or that the value is null.
 201   * @method static bool nullOrStartsWith(mixed|null $string, string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars or that the value is null.
 202   * @method static bool nullOrString(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is a string or that the value is null.
 203   * @method static bool nullOrSubclassOf(mixed|null $value, string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name or that the value is null.
 204   * @method static bool nullOrTrue(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True or that the value is null.
 205   * @method static bool nullOrUrl(mixed|null $value, string|callable $message = null, string $propertyPath = null) Assert that value is an URL or that the value is null.
 206   * @method static bool nullOrUuid(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID or that the value is null.
 207   * @method static bool nullOrVersion(string|null $version1, string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions or that the value is null.
 208   * @method static bool nullOrWriteable(string|null $value, string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable or that the value is null.
 209   */
 210  class Assertion
 211  {
 212      const INVALID_FLOAT = 9;
 213      const INVALID_INTEGER = 10;
 214      const INVALID_DIGIT = 11;
 215      const INVALID_INTEGERISH = 12;
 216      const INVALID_BOOLEAN = 13;
 217      const VALUE_EMPTY = 14;
 218      const VALUE_NULL = 15;
 219      const VALUE_NOT_NULL = 25;
 220      const INVALID_STRING = 16;
 221      const INVALID_REGEX = 17;
 222      const INVALID_MIN_LENGTH = 18;
 223      const INVALID_MAX_LENGTH = 19;
 224      const INVALID_STRING_START = 20;
 225      const INVALID_STRING_CONTAINS = 21;
 226      const INVALID_CHOICE = 22;
 227      const INVALID_NUMERIC = 23;
 228      const INVALID_ARRAY = 24;
 229      const INVALID_KEY_EXISTS = 26;
 230      const INVALID_NOT_BLANK = 27;
 231      const INVALID_INSTANCE_OF = 28;
 232      const INVALID_SUBCLASS_OF = 29;
 233      const INVALID_RANGE = 30;
 234      const INVALID_ALNUM = 31;
 235      const INVALID_TRUE = 32;
 236      const INVALID_EQ = 33;
 237      const INVALID_SAME = 34;
 238      const INVALID_MIN = 35;
 239      const INVALID_MAX = 36;
 240      const INVALID_LENGTH = 37;
 241      const INVALID_FALSE = 38;
 242      const INVALID_STRING_END = 39;
 243      const INVALID_UUID = 40;
 244      const INVALID_COUNT = 41;
 245      const INVALID_NOT_EQ = 42;
 246      const INVALID_NOT_SAME = 43;
 247      const INVALID_TRAVERSABLE = 44;
 248      const INVALID_ARRAY_ACCESSIBLE = 45;
 249      const INVALID_KEY_ISSET = 46;
 250      const INVALID_VALUE_IN_ARRAY = 47;
 251      const INVALID_E164 = 48;
 252      const INVALID_BASE64 = 49;
 253      const INVALID_NOT_REGEX = 50;
 254      const INVALID_DIRECTORY = 101;
 255      const INVALID_FILE = 102;
 256      const INVALID_READABLE = 103;
 257      const INVALID_WRITEABLE = 104;
 258      const INVALID_CLASS = 105;
 259      const INVALID_INTERFACE = 106;
 260      const INVALID_FILE_NOT_EXISTS = 107;
 261      const INVALID_EMAIL = 201;
 262      const INTERFACE_NOT_IMPLEMENTED = 202;
 263      const INVALID_URL = 203;
 264      const INVALID_NOT_INSTANCE_OF = 204;
 265      const VALUE_NOT_EMPTY = 205;
 266      const INVALID_JSON_STRING = 206;
 267      const INVALID_OBJECT = 207;
 268      const INVALID_METHOD = 208;
 269      const INVALID_SCALAR = 209;
 270      const INVALID_LESS = 210;
 271      const INVALID_LESS_OR_EQUAL = 211;
 272      const INVALID_GREATER = 212;
 273      const INVALID_GREATER_OR_EQUAL = 213;
 274      const INVALID_DATE = 214;
 275      const INVALID_CALLABLE = 215;
 276      const INVALID_KEY_NOT_EXISTS = 216;
 277      const INVALID_SATISFY = 217;
 278      const INVALID_IP = 218;
 279      const INVALID_BETWEEN = 219;
 280      const INVALID_BETWEEN_EXCLUSIVE = 220;
 281      const INVALID_EXTENSION = 222;
 282      const INVALID_CONSTANT = 221;
 283      const INVALID_VERSION = 223;
 284      const INVALID_PROPERTY = 224;
 285      const INVALID_RESOURCE = 225;
 286      const INVALID_COUNTABLE = 226;
 287      const INVALID_MIN_COUNT = 227;
 288      const INVALID_MAX_COUNT = 228;
 289      const INVALID_STRING_NOT_CONTAINS = 229;
 290  
 291      /**
 292       * Exception to throw when an assertion failed.
 293       *
 294       * @var string
 295       */
 296      protected static $exceptionClass = InvalidArgumentException::class;
 297  
 298      /**
 299       * Assert that two values are equal (using ==).
 300       *
 301       * @param mixed $value
 302       * @param mixed $value2
 303       * @param string|callable|null $message
 304       * @param string|null $propertyPath
 305       *
 306       * @return bool
 307       *
 308       * @throws AssertionFailedException
 309       */
 310      public static function eq($value, $value2, $message = null, string $propertyPath = null): bool
 311      {
 312          if ($value != $value2) {
 313              $message = \sprintf(
 314                  static::generateMessage($message ?: 'Value "%s" does not equal expected value "%s".'),
 315                  static::stringify($value),
 316                  static::stringify($value2)
 317              );
 318  
 319              throw static::createException($value, $message, static::INVALID_EQ, $propertyPath, ['expected' => $value2]);
 320          }
 321  
 322          return true;
 323      }
 324  
 325      /**
 326       * Assert that the array contains the subset.
 327       *
 328       * @param mixed $value
 329       * @param mixed $value2
 330       * @param string|callable|null $message
 331       * @param string|null $propertyPath
 332       *
 333       * @return bool
 334       *
 335       * @throws AssertionFailedException
 336       */
 337      public static function eqArraySubset($value, $value2, $message = null, string $propertyPath = null): bool
 338      {
 339          static::isArray($value, $message, $propertyPath);
 340          static::isArray($value2, $message, $propertyPath);
 341  
 342          $patched = \array_replace_recursive($value, $value2);
 343          static::eq($patched, $value, $message, $propertyPath);
 344  
 345          return true;
 346      }
 347  
 348      /**
 349       * Assert that two values are the same (using ===).
 350       *
 351       * @param mixed $value
 352       * @param mixed $value2
 353       * @param string|callable|null $message
 354       * @param string|null $propertyPath
 355       *
 356       * @return bool
 357       *
 358       * @throws AssertionFailedException
 359       */
 360      public static function same($value, $value2, $message = null, string $propertyPath = null): bool
 361      {
 362          if ($value !== $value2) {
 363              $message = \sprintf(
 364                  static::generateMessage($message ?: 'Value "%s" is not the same as expected value "%s".'),
 365                  static::stringify($value),
 366                  static::stringify($value2)
 367              );
 368  
 369              throw static::createException($value, $message, static::INVALID_SAME, $propertyPath, ['expected' => $value2]);
 370          }
 371  
 372          return true;
 373      }
 374  
 375      /**
 376       * Assert that two values are not equal (using ==).
 377       *
 378       * @param mixed $value1
 379       * @param mixed $value2
 380       * @param string|callable|null $message
 381       * @param string|null $propertyPath
 382       *
 383       * @return bool
 384       *
 385       * @throws AssertionFailedException
 386       */
 387      public static function notEq($value1, $value2, $message = null, string $propertyPath = null): bool
 388      {
 389          if ($value1 == $value2) {
 390              $message = \sprintf(
 391                  static::generateMessage($message ?: 'Value "%s" was not expected to be equal to value "%s".'),
 392                  static::stringify($value1),
 393                  static::stringify($value2)
 394              );
 395              throw static::createException($value1, $message, static::INVALID_NOT_EQ, $propertyPath, ['expected' => $value2]);
 396          }
 397  
 398          return true;
 399      }
 400  
 401      /**
 402       * Assert that two values are not the same (using ===).
 403       *
 404       * @param mixed $value1
 405       * @param mixed $value2
 406       * @param string|callable|null $message
 407       * @param string|null $propertyPath
 408       *
 409       * @return bool
 410       *
 411       * @throws AssertionFailedException
 412       */
 413      public static function notSame($value1, $value2, $message = null, string $propertyPath = null): bool
 414      {
 415          if ($value1 === $value2) {
 416              $message = \sprintf(
 417                  static::generateMessage($message ?: 'Value "%s" was not expected to be the same as value "%s".'),
 418                  static::stringify($value1),
 419                  static::stringify($value2)
 420              );
 421              throw static::createException($value1, $message, static::INVALID_NOT_SAME, $propertyPath, ['expected' => $value2]);
 422          }
 423  
 424          return true;
 425      }
 426  
 427      /**
 428       * Assert that value is not in array of choices.
 429       *
 430       * @param mixed $value
 431       * @param array $choices
 432       * @param string|callable|null $message
 433       * @param string|null $propertyPath
 434       *
 435       * @return bool
 436       *
 437       * @throws AssertionFailedException
 438       */
 439      public static function notInArray($value, array $choices, $message = null, string $propertyPath = null): bool
 440      {
 441          if (true === \in_array($value, $choices)) {
 442              $message = \sprintf(
 443                  static::generateMessage($message ?: 'Value "%s" was not expected to be an element of the values: %s'),
 444                  static::stringify($value),
 445                  static::stringify($choices)
 446              );
 447              throw static::createException($value, $message, static::INVALID_VALUE_IN_ARRAY, $propertyPath, ['choices' => $choices]);
 448          }
 449  
 450          return true;
 451      }
 452  
 453      /**
 454       * Assert that value is a php integer.
 455       *
 456       * @param mixed $value
 457       * @param string|callable|null $message
 458       * @param string|null $propertyPath
 459       *
 460       * @return bool
 461       *
 462       * @throws AssertionFailedException
 463       */
 464      public static function integer($value, $message = null, string $propertyPath = null): bool
 465      {
 466          if (!\is_int($value)) {
 467              $message = \sprintf(
 468                  static::generateMessage($message ?: 'Value "%s" is not an integer.'),
 469                  static::stringify($value)
 470              );
 471  
 472              throw static::createException($value, $message, static::INVALID_INTEGER, $propertyPath);
 473          }
 474  
 475          return true;
 476      }
 477  
 478      /**
 479       * Assert that value is a php float.
 480       *
 481       * @param mixed $value
 482       * @param string|callable|null $message
 483       * @param string|null $propertyPath
 484       *
 485       * @return bool
 486       *
 487       * @throws AssertionFailedException
 488       */
 489      public static function float($value, $message = null, string $propertyPath = null): bool
 490      {
 491          if (!\is_float($value)) {
 492              $message = \sprintf(
 493                  static::generateMessage($message ?: 'Value "%s" is not a float.'),
 494                  static::stringify($value)
 495              );
 496  
 497              throw static::createException($value, $message, static::INVALID_FLOAT, $propertyPath);
 498          }
 499  
 500          return true;
 501      }
 502  
 503      /**
 504       * Validates if an integer or integerish is a digit.
 505       *
 506       * @param mixed $value
 507       * @param string|callable|null $message
 508       * @param string|null $propertyPath
 509       *
 510       * @return bool
 511       *
 512       * @throws AssertionFailedException
 513       */
 514      public static function digit($value, $message = null, string $propertyPath = null): bool
 515      {
 516          if (!\ctype_digit((string)$value)) {
 517              $message = \sprintf(
 518                  static::generateMessage($message ?: 'Value "%s" is not a digit.'),
 519                  static::stringify($value)
 520              );
 521  
 522              throw static::createException($value, $message, static::INVALID_DIGIT, $propertyPath);
 523          }
 524  
 525          return true;
 526      }
 527  
 528      /**
 529       * Assert that value is a php integer'ish.
 530       *
 531       * @param mixed $value
 532       * @param string|callable|null $message
 533       * @param string|null $propertyPath
 534       *
 535       * @return bool
 536       *
 537       * @throws AssertionFailedException
 538       */
 539      public static function integerish($value, $message = null, string $propertyPath = null): bool
 540      {
 541          if (
 542              \is_resource($value) ||
 543              \is_object($value) ||
 544              \is_bool($value) ||
 545              \is_null($value) ||
 546              \is_array($value) ||
 547              (\is_string($value) && '' == $value) ||
 548              (
 549                  \strval(\intval($value)) !== \strval($value) &&
 550                  \strval(\intval($value)) !== \strval(\ltrim($value, '0')) &&
 551                  '' !== \strval(\intval($value)) &&
 552                  '' !== \strval(\ltrim($value, '0'))
 553              )
 554          ) {
 555              $message = \sprintf(
 556                  static::generateMessage($message ?: 'Value "%s" is not an integer or a number castable to integer.'),
 557                  static::stringify($value)
 558              );
 559  
 560              throw static::createException($value, $message, static::INVALID_INTEGERISH, $propertyPath);
 561          }
 562  
 563          return true;
 564      }
 565  
 566      /**
 567       * Assert that value is php boolean.
 568       *
 569       * @param mixed $value
 570       * @param string|callable|null $message
 571       * @param string|null $propertyPath
 572       *
 573       * @return bool
 574       *
 575       * @throws AssertionFailedException
 576       */
 577      public static function boolean($value, $message = null, string $propertyPath = null): bool
 578      {
 579          if (!\is_bool($value)) {
 580              $message = \sprintf(
 581                  static::generateMessage($message ?: 'Value "%s" is not a boolean.'),
 582                  static::stringify($value)
 583              );
 584  
 585              throw static::createException($value, $message, static::INVALID_BOOLEAN, $propertyPath);
 586          }
 587  
 588          return true;
 589      }
 590  
 591      /**
 592       * Assert that value is a PHP scalar.
 593       *
 594       * @param mixed $value
 595       * @param string|callable|null $message
 596       * @param string|null $propertyPath
 597       *
 598       * @return bool
 599       *
 600       * @throws AssertionFailedException
 601       */
 602      public static function scalar($value, $message = null, string $propertyPath = null): bool
 603      {
 604          if (!\is_scalar($value)) {
 605              $message = \sprintf(
 606                  static::generateMessage($message ?: 'Value "%s" is not a scalar.'),
 607                  static::stringify($value)
 608              );
 609  
 610              throw static::createException($value, $message, static::INVALID_SCALAR, $propertyPath);
 611          }
 612  
 613          return true;
 614      }
 615  
 616      /**
 617       * Assert that value is not empty.
 618       *
 619       * @param mixed $value
 620       * @param string|callable|null $message
 621       * @param string|null $propertyPath
 622       *
 623       * @return bool
 624       *
 625       * @throws AssertionFailedException
 626       */
 627      public static function notEmpty($value, $message = null, string $propertyPath = null): bool
 628      {
 629          if (empty($value)) {
 630              $message = \sprintf(
 631                  static::generateMessage($message ?: 'Value "%s" is empty, but non empty value was expected.'),
 632                  static::stringify($value)
 633              );
 634  
 635              throw static::createException($value, $message, static::VALUE_EMPTY, $propertyPath);
 636          }
 637  
 638          return true;
 639      }
 640  
 641      /**
 642       * Assert that value is empty.
 643       *
 644       * @param mixed $value
 645       * @param string|callable|null $message
 646       * @param string|null $propertyPath
 647       *
 648       * @return bool
 649       *
 650       * @throws AssertionFailedException
 651       */
 652      public static function noContent($value, $message = null, string $propertyPath = null): bool
 653      {
 654          if (!empty($value)) {
 655              $message = \sprintf(
 656                  static::generateMessage($message ?: 'Value "%s" is not empty, but empty value was expected.'),
 657                  static::stringify($value)
 658              );
 659  
 660              throw static::createException($value, $message, static::VALUE_NOT_EMPTY, $propertyPath);
 661          }
 662  
 663          return true;
 664      }
 665  
 666      /**
 667       * Assert that value is null.
 668       *
 669       * @param mixed $value
 670       * @param string|callable|null $message
 671       * @param string|null $propertyPath
 672       *
 673       * @return bool
 674       */
 675      public static function null($value, $message = null, string $propertyPath = null): bool
 676      {
 677          if (null !== $value) {
 678              $message = \sprintf(
 679                  static::generateMessage($message ?: 'Value "%s" is not null, but null value was expected.'),
 680                  static::stringify($value)
 681              );
 682  
 683              throw static::createException($value, $message, static::VALUE_NOT_NULL, $propertyPath);
 684          }
 685  
 686          return true;
 687      }
 688  
 689      /**
 690       * Assert that value is not null.
 691       *
 692       * @param mixed $value
 693       * @param string|callable|null $message
 694       * @param string|null $propertyPath
 695       *
 696       * @return bool
 697       *
 698       * @throws AssertionFailedException
 699       */
 700      public static function notNull($value, $message = null, string $propertyPath = null): bool
 701      {
 702          if (null === $value) {
 703              $message = \sprintf(
 704                  static::generateMessage($message ?: 'Value "%s" is null, but non null value was expected.'),
 705                  static::stringify($value)
 706              );
 707  
 708              throw static::createException($value, $message, static::VALUE_NULL, $propertyPath);
 709          }
 710  
 711          return true;
 712      }
 713  
 714      /**
 715       * Assert that value is a string.
 716       *
 717       * @param mixed $value
 718       * @param string|callable|null $message
 719       * @param string|null $propertyPath
 720       *
 721       * @return bool
 722       *
 723       * @throws AssertionFailedException
 724       */
 725      public static function string($value, $message = null, string $propertyPath = null)
 726      {
 727          if (!\is_string($value)) {
 728              $message = \sprintf(
 729                  static::generateMessage($message ?: 'Value "%s" expected to be string, type %s given.'),
 730                  static::stringify($value),
 731                  \gettype($value)
 732              );
 733  
 734              throw static::createException($value, $message, static::INVALID_STRING, $propertyPath);
 735          }
 736  
 737          return true;
 738      }
 739  
 740      /**
 741       * Assert that value matches a regex.
 742       *
 743       * @param mixed $value
 744       * @param string $pattern
 745       * @param string|callable|null $message
 746       * @param string|null $propertyPath
 747       *
 748       * @return bool
 749       *
 750       * @throws AssertionFailedException
 751       */
 752      public static function regex($value, $pattern, $message = null, string $propertyPath = null): bool
 753      {
 754          static::string($value, $message, $propertyPath);
 755  
 756          if (!\preg_match($pattern, $value)) {
 757              $message = \sprintf(
 758                  static::generateMessage($message ?: 'Value "%s" does not match expression.'),
 759                  static::stringify($value)
 760              );
 761  
 762              throw static::createException($value, $message, static::INVALID_REGEX, $propertyPath, ['pattern' => $pattern]);
 763          }
 764  
 765          return true;
 766      }
 767  
 768      /**
 769       * Assert that value does not match a regex.
 770       *
 771       * @param mixed $value
 772       * @param string $pattern
 773       * @param string|callable|null $message
 774       * @param string|null $propertyPath
 775       *
 776       * @return bool
 777       *
 778       * @throws AssertionFailedException
 779       */
 780      public static function notRegex($value, $pattern, $message = null, string $propertyPath = null): bool
 781      {
 782          static::string($value, $message, $propertyPath);
 783  
 784          if (\preg_match($pattern, $value)) {
 785              $message = \sprintf(
 786                  static::generateMessage($message ?: 'Value "%s" matches expression.'),
 787                  static::stringify($value)
 788              );
 789  
 790              throw static::createException($value, $message, static::INVALID_NOT_REGEX, $propertyPath, ['pattern' => $pattern]);
 791          }
 792  
 793          return true;
 794      }
 795  
 796      /**
 797       * Assert that string has a given length.
 798       *
 799       * @param mixed $value
 800       * @param int $length
 801       * @param string|callable|null $message
 802       * @param string|null $propertyPath
 803       * @param string $encoding
 804       *
 805       * @return bool
 806       *
 807       * @throws AssertionFailedException
 808       */
 809      public static function length($value, $length, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
 810      {
 811          static::string($value, $message, $propertyPath);
 812  
 813          if (\mb_strlen($value, $encoding) !== $length) {
 814              $message = \sprintf(
 815                  static::generateMessage($message ?: 'Value "%s" has to be %d exactly characters long, but length is %d.'),
 816                  static::stringify($value),
 817                  $length,
 818                  \mb_strlen($value, $encoding)
 819              );
 820  
 821              throw static::createException($value, $message, static::INVALID_LENGTH, $propertyPath, ['length' => $length, 'encoding' => $encoding]);
 822          }
 823  
 824          return true;
 825      }
 826  
 827      /**
 828       * Assert that a string is at least $minLength chars long.
 829       *
 830       * @param mixed $value
 831       * @param int $minLength
 832       * @param string|callable|null $message
 833       * @param string|null $propertyPath
 834       * @param string $encoding
 835       *
 836       * @return bool
 837       *
 838       * @throws AssertionFailedException
 839       */
 840      public static function minLength($value, $minLength, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
 841      {
 842          static::string($value, $message, $propertyPath);
 843  
 844          if (\mb_strlen($value, $encoding) < $minLength) {
 845              $message = \sprintf(
 846                  static::generateMessage($message ?: 'Value "%s" is too short, it should have at least %d characters, but only has %d characters.'),
 847                  static::stringify($value),
 848                  $minLength,
 849                  \mb_strlen($value, $encoding)
 850              );
 851  
 852              throw static::createException($value, $message, static::INVALID_MIN_LENGTH, $propertyPath, ['min_length' => $minLength, 'encoding' => $encoding]);
 853          }
 854  
 855          return true;
 856      }
 857  
 858      /**
 859       * Assert that string value is not longer than $maxLength chars.
 860       *
 861       * @param mixed $value
 862       * @param int $maxLength
 863       * @param string|callable|null $message
 864       * @param string|null $propertyPath
 865       * @param string $encoding
 866       *
 867       * @return bool
 868       *
 869       * @throws AssertionFailedException
 870       */
 871      public static function maxLength($value, $maxLength, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
 872      {
 873          static::string($value, $message, $propertyPath);
 874  
 875          if (\mb_strlen($value, $encoding) > $maxLength) {
 876              $message = \sprintf(
 877                  static::generateMessage($message ?: 'Value "%s" is too long, it should have no more than %d characters, but has %d characters.'),
 878                  static::stringify($value),
 879                  $maxLength,
 880                  \mb_strlen($value, $encoding)
 881              );
 882  
 883              throw static::createException($value, $message, static::INVALID_MAX_LENGTH, $propertyPath, ['max_length' => $maxLength, 'encoding' => $encoding]);
 884          }
 885  
 886          return true;
 887      }
 888  
 889      /**
 890       * Assert that string length is between min and max lengths.
 891       *
 892       * @param mixed $value
 893       * @param int $minLength
 894       * @param int $maxLength
 895       * @param string|callable|null $message
 896       * @param string|null $propertyPath
 897       * @param string $encoding
 898       *
 899       * @return bool
 900       *
 901       * @throws AssertionFailedException
 902       */
 903      public static function betweenLength($value, $minLength, $maxLength, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
 904      {
 905          static::string($value, $message, $propertyPath);
 906          static::minLength($value, $minLength, $message, $propertyPath, $encoding);
 907          static::maxLength($value, $maxLength, $message, $propertyPath, $encoding);
 908  
 909          return true;
 910      }
 911  
 912      /**
 913       * Assert that string starts with a sequence of chars.
 914       *
 915       * @param mixed $string
 916       * @param string $needle
 917       * @param string|callable|null $message
 918       * @param string|null $propertyPath
 919       * @param string $encoding
 920       *
 921       * @return bool
 922       *
 923       * @throws AssertionFailedException
 924       */
 925      public static function startsWith($string, $needle, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
 926      {
 927          static::string($string, $message, $propertyPath);
 928  
 929          if (0 !== \mb_strpos($string, $needle, null, $encoding)) {
 930              $message = \sprintf(
 931                  static::generateMessage($message ?: 'Value "%s" does not start with "%s".'),
 932                  static::stringify($string),
 933                  static::stringify($needle)
 934              );
 935  
 936              throw static::createException($string, $message, static::INVALID_STRING_START, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]);
 937          }
 938  
 939          return true;
 940      }
 941  
 942      /**
 943       * Assert that string ends with a sequence of chars.
 944       *
 945       * @param mixed $string
 946       * @param string $needle
 947       * @param string|callable|null $message
 948       * @param string|null $propertyPath
 949       * @param string $encoding
 950       *
 951       * @return bool
 952       *
 953       * @throws AssertionFailedException
 954       */
 955      public static function endsWith($string, $needle, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
 956      {
 957          static::string($string, $message, $propertyPath);
 958  
 959          $stringPosition = \mb_strlen($string, $encoding) - \mb_strlen($needle, $encoding);
 960  
 961          if (\mb_strripos($string, $needle, null, $encoding) !== $stringPosition) {
 962              $message = \sprintf(
 963                  static::generateMessage($message ?: 'Value "%s" does not end with "%s".'),
 964                  static::stringify($string),
 965                  static::stringify($needle)
 966              );
 967  
 968              throw static::createException($string, $message, static::INVALID_STRING_END, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]);
 969          }
 970  
 971          return true;
 972      }
 973  
 974      /**
 975       * Assert that string contains a sequence of chars.
 976       *
 977       * @param mixed $string
 978       * @param string $needle
 979       * @param string|callable|null $message
 980       * @param string|null $propertyPath
 981       * @param string $encoding
 982       *
 983       * @return bool
 984       *
 985       * @throws AssertionFailedException
 986       */
 987      public static function contains($string, $needle, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
 988      {
 989          static::string($string, $message, $propertyPath);
 990  
 991          if (false === \mb_strpos($string, $needle, null, $encoding)) {
 992              $message = \sprintf(
 993                  static::generateMessage($message ?: 'Value "%s" does not contain "%s".'),
 994                  static::stringify($string),
 995                  static::stringify($needle)
 996              );
 997  
 998              throw static::createException($string, $message, static::INVALID_STRING_CONTAINS, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]);
 999          }
1000  
1001          return true;
1002      }
1003  
1004      /**
1005       * Assert that string does not contains a sequence of chars.
1006       *
1007       * @param mixed $string
1008       * @param string $needle
1009       * @param string|callable|null $message
1010       * @param string|null $propertyPath
1011       * @param string $encoding
1012       *
1013       * @return bool
1014       *
1015       * @throws AssertionFailedException
1016       */
1017      public static function notContains($string, $needle, $message = null, string $propertyPath = null, $encoding = 'utf8'): bool
1018      {
1019          static::string($string, $message, $propertyPath);
1020  
1021          if (false !== \mb_strpos($string, $needle, null, $encoding)) {
1022              $message = \sprintf(
1023                  static::generateMessage($message ?: 'Value "%s" contains "%s".'),
1024                  static::stringify($string),
1025                  static::stringify($needle)
1026              );
1027  
1028              throw static::createException($string, $message, static::INVALID_STRING_NOT_CONTAINS, $propertyPath, ['needle' => $needle, 'encoding' => $encoding]);
1029          }
1030  
1031          return true;
1032      }
1033  
1034      /**
1035       * Assert that value is in array of choices.
1036       *
1037       * @param mixed $value
1038       * @param array $choices
1039       * @param string|callable|null $message
1040       * @param string|null $propertyPath
1041       *
1042       * @return bool
1043       *
1044       * @throws AssertionFailedException
1045       */
1046      public static function choice($value, array $choices, $message = null, string $propertyPath = null): bool
1047      {
1048          if (!\in_array($value, $choices, true)) {
1049              $message = \sprintf(
1050                  static::generateMessage($message ?: 'Value "%s" is not an element of the valid values: %s'),
1051                  static::stringify($value),
1052                  \implode(', ', \array_map([\get_called_class(), 'stringify'], $choices))
1053              );
1054  
1055              throw static::createException($value, $message, static::INVALID_CHOICE, $propertyPath, ['choices' => $choices]);
1056          }
1057  
1058          return true;
1059      }
1060  
1061      /**
1062       * Assert that value is in array of choices.
1063       *
1064       * This is an alias of {@see choice()}.
1065       *
1066       * @param mixed $value
1067       * @param array $choices
1068       * @param string|callable|null $message
1069       * @param string|null $propertyPath
1070       *
1071       * @return bool
1072       *
1073       * @throws AssertionFailedException
1074       */
1075      public static function inArray($value, array $choices, $message = null, string $propertyPath = null): bool
1076      {
1077          return static::choice($value, $choices, $message, $propertyPath);
1078      }
1079  
1080      /**
1081       * Assert that value is numeric.
1082       *
1083       * @param mixed $value
1084       * @param string|callable|null $message
1085       * @param string|null $propertyPath
1086       *
1087       * @return bool
1088       *
1089       * @throws AssertionFailedException
1090       */
1091      public static function numeric($value, $message = null, string $propertyPath = null): bool
1092      {
1093          if (!\is_numeric($value)) {
1094              $message = \sprintf(
1095                  static::generateMessage($message ?: 'Value "%s" is not numeric.'),
1096                  static::stringify($value)
1097              );
1098  
1099              throw static::createException($value, $message, static::INVALID_NUMERIC, $propertyPath);
1100          }
1101  
1102          return true;
1103      }
1104  
1105      /**
1106       * Assert that value is a resource.
1107       *
1108       * @param mixed $value
1109       * @param string|callable|null $message
1110       * @param string|null $propertyPath
1111       *
1112       * @return bool
1113       */
1114      public static function isResource($value, $message = null, string $propertyPath = null): bool
1115      {
1116          if (!\is_resource($value)) {
1117              $message = \sprintf(
1118                  static::generateMessage($message ?: 'Value "%s" is not a resource.'),
1119                  static::stringify($value)
1120              );
1121  
1122              throw static::createException($value, $message, static::INVALID_RESOURCE, $propertyPath);
1123          }
1124  
1125          return true;
1126      }
1127  
1128      /**
1129       * Assert that value is an array.
1130       *
1131       * @param mixed $value
1132       * @param string|callable|null $message
1133       * @param string|null $propertyPath
1134       *
1135       * @return bool
1136       *
1137       * @throws AssertionFailedException
1138       */
1139      public static function isArray($value, $message = null, string $propertyPath = null): bool
1140      {
1141          if (!\is_array($value)) {
1142              $message = \sprintf(
1143                  static::generateMessage($message ?: 'Value "%s" is not an array.'),
1144                  static::stringify($value)
1145              );
1146  
1147              throw static::createException($value, $message, static::INVALID_ARRAY, $propertyPath);
1148          }
1149  
1150          return true;
1151      }
1152  
1153      /**
1154       * Assert that value is an array or a traversable object.
1155       *
1156       * @param mixed $value
1157       * @param string|callable|null $message
1158       * @param string|null $propertyPath
1159       *
1160       * @return bool
1161       *
1162       * @throws AssertionFailedException
1163       */
1164      public static function isTraversable($value, $message = null, string $propertyPath = null): bool
1165      {
1166          if (!\is_array($value) && !$value instanceof Traversable) {
1167              $message = \sprintf(
1168                  static::generateMessage($message ?: 'Value "%s" is not an array and does not implement Traversable.'),
1169                  static::stringify($value)
1170              );
1171  
1172              throw static::createException($value, $message, static::INVALID_TRAVERSABLE, $propertyPath);
1173          }
1174  
1175          return true;
1176      }
1177  
1178      /**
1179       * Assert that value is an array or an array-accessible object.
1180       *
1181       * @param mixed $value
1182       * @param string|callable|null $message
1183       * @param string|null $propertyPath
1184       *
1185       * @return bool
1186       *
1187       * @throws AssertionFailedException
1188       */
1189      public static function isArrayAccessible($value, $message = null, string $propertyPath = null): bool
1190      {
1191          if (!\is_array($value) && !$value instanceof ArrayAccess) {
1192              $message = \sprintf(
1193                  static::generateMessage($message ?: 'Value "%s" is not an array and does not implement ArrayAccess.'),
1194                  static::stringify($value)
1195              );
1196  
1197              throw static::createException($value, $message, static::INVALID_ARRAY_ACCESSIBLE, $propertyPath);
1198          }
1199  
1200          return true;
1201      }
1202  
1203      /**
1204       * Assert that value is countable.
1205       *
1206       * @param array|Countable|ResourceBundle|SimpleXMLElement $value
1207       * @param string|callable|null $message
1208       * @param string|null $propertyPath
1209       *
1210       * @return bool
1211       *
1212       * @throws AssertionFailedException
1213       */
1214      public static function isCountable($value, $message = null, string $propertyPath = null): bool
1215      {
1216          if (\function_exists('is_countable')) {
1217              $assert = \is_countable($value);
1218          } else {
1219              $assert = \is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXMLElement;
1220          }
1221  
1222          if (!$assert) {
1223              $message = \sprintf(
1224                  static::generateMessage($message ?: 'Value "%s" is not an array and does not implement Countable.'),
1225                  static::stringify($value)
1226              );
1227  
1228              throw static::createException($value, $message, static::INVALID_COUNTABLE, $propertyPath);
1229          }
1230  
1231          return true;
1232      }
1233  
1234      /**
1235       * Assert that key exists in an array.
1236       *
1237       * @param mixed $value
1238       * @param string|int $key
1239       * @param string|callable|null $message
1240       * @param string|null $propertyPath
1241       *
1242       * @return bool
1243       *
1244       * @throws AssertionFailedException
1245       */
1246      public static function keyExists($value, $key, $message = null, string $propertyPath = null): bool
1247      {
1248          static::isArray($value, $message, $propertyPath);
1249  
1250          if (!\array_key_exists($key, $value)) {
1251              $message = \sprintf(
1252                  static::generateMessage($message ?: 'Array does not contain an element with key "%s"'),
1253                  static::stringify($key)
1254              );
1255  
1256              throw static::createException($value, $message, static::INVALID_KEY_EXISTS, $propertyPath, ['key' => $key]);
1257          }
1258  
1259          return true;
1260      }
1261  
1262      /**
1263       * Assert that key does not exist in an array.
1264       *
1265       * @param mixed $value
1266       * @param string|int $key
1267       * @param string|callable|null $message
1268       * @param string|null $propertyPath
1269       *
1270       * @return bool
1271       *
1272       * @throws AssertionFailedException
1273       */
1274      public static function keyNotExists($value, $key, $message = null, string $propertyPath = null): bool
1275      {
1276          static::isArray($value, $message, $propertyPath);
1277  
1278          if (\array_key_exists($key, $value)) {
1279              $message = \sprintf(
1280                  static::generateMessage($message ?: 'Array contains an element with key "%s"'),
1281                  static::stringify($key)
1282              );
1283  
1284              throw static::createException($value, $message, static::INVALID_KEY_NOT_EXISTS, $propertyPath, ['key' => $key]);
1285          }
1286  
1287          return true;
1288      }
1289  
1290      /**
1291       * Assert that key exists in an array/array-accessible object using isset().
1292       *
1293       * @param mixed $value
1294       * @param string|int $key
1295       * @param string|callable|null $message
1296       * @param string|null $propertyPath
1297       *
1298       * @return bool
1299       *
1300       * @throws AssertionFailedException
1301       */
1302      public static function keyIsset($value, $key, $message = null, string $propertyPath = null): bool
1303      {
1304          static::isArrayAccessible($value, $message, $propertyPath);
1305  
1306          if (!isset($value[$key])) {
1307              $message = \sprintf(
1308                  static::generateMessage($message ?: 'The element with key "%s" was not found'),
1309                  static::stringify($key)
1310              );
1311  
1312              throw static::createException($value, $message, static::INVALID_KEY_ISSET, $propertyPath, ['key' => $key]);
1313          }
1314  
1315          return true;
1316      }
1317  
1318      /**
1319       * Assert that key exists in an array/array-accessible object and its value is not empty.
1320       *
1321       * @param mixed $value
1322       * @param string|int $key
1323       * @param string|callable|null $message
1324       * @param string|null $propertyPath
1325       *
1326       * @return bool
1327       *
1328       * @throws AssertionFailedException
1329       */
1330      public static function notEmptyKey($value, $key, $message = null, string $propertyPath = null): bool
1331      {
1332          static::keyIsset($value, $key, $message, $propertyPath);
1333          static::notEmpty($value[$key], $message, $propertyPath);
1334  
1335          return true;
1336      }
1337  
1338      /**
1339       * Assert that value is not blank.
1340       *
1341       * @param mixed $value
1342       * @param string|callable|null $message
1343       * @param string|null $propertyPath
1344       *
1345       * @return bool
1346       *
1347       * @throws AssertionFailedException
1348       */
1349      public static function notBlank($value, $message = null, string $propertyPath = null): bool
1350      {
1351          if (false === $value || (empty($value) && '0' != $value) || (\is_string($value) && '' === \trim($value))) {
1352              $message = \sprintf(
1353                  static::generateMessage($message ?: 'Value "%s" is blank, but was expected to contain a value.'),
1354                  static::stringify($value)
1355              );
1356  
1357              throw static::createException($value, $message, static::INVALID_NOT_BLANK, $propertyPath);
1358          }
1359  
1360          return true;
1361      }
1362  
1363      /**
1364       * Assert that value is instance of given class-name.
1365       *
1366       * @param mixed $value
1367       * @param string $className
1368       * @param string|callable|null $message
1369       * @param string|null $propertyPath
1370       *
1371       * @return bool
1372       *
1373       * @throws AssertionFailedException
1374       */
1375      public static function isInstanceOf($value, $className, $message = null, string $propertyPath = null): bool
1376      {
1377          if (!($value instanceof $className)) {
1378              $message = \sprintf(
1379                  static::generateMessage($message ?: 'Class "%s" was expected to be instanceof of "%s" but is not.'),
1380                  static::stringify($value),
1381                  $className
1382              );
1383  
1384              throw static::createException($value, $message, static::INVALID_INSTANCE_OF, $propertyPath, ['class' => $className]);
1385          }
1386  
1387          return true;
1388      }
1389  
1390      /**
1391       * Assert that value is not instance of given class-name.
1392       *
1393       * @param mixed $value
1394       * @param string $className
1395       * @param string|callable|null $message
1396       * @param string|null $propertyPath
1397       *
1398       * @return bool
1399       *
1400       * @throws AssertionFailedException
1401       */
1402      public static function notIsInstanceOf($value, $className, $message = null, string $propertyPath = null): bool
1403      {
1404          if ($value instanceof $className) {
1405              $message = \sprintf(
1406                  static::generateMessage($message ?: 'Class "%s" was not expected to be instanceof of "%s".'),
1407                  static::stringify($value),
1408                  $className
1409              );
1410  
1411              throw static::createException($value, $message, static::INVALID_NOT_INSTANCE_OF, $propertyPath, ['class' => $className]);
1412          }
1413  
1414          return true;
1415      }
1416  
1417      /**
1418       * Assert that value is subclass of given class-name.
1419       *
1420       * @param mixed $value
1421       * @param string $className
1422       * @param string|callable|null $message
1423       * @param string|null $propertyPath
1424       *
1425       * @return bool
1426       *
1427       * @throws AssertionFailedException
1428       */
1429      public static function subclassOf($value, $className, $message = null, string $propertyPath = null): bool
1430      {
1431          if (!\is_subclass_of($value, $className)) {
1432              $message = \sprintf(
1433                  static::generateMessage($message ?: 'Class "%s" was expected to be subclass of "%s".'),
1434                  static::stringify($value),
1435                  $className
1436              );
1437  
1438              throw static::createException($value, $message, static::INVALID_SUBCLASS_OF, $propertyPath, ['class' => $className]);
1439          }
1440  
1441          return true;
1442      }
1443  
1444      /**
1445       * Assert that value is in range of numbers.
1446       *
1447       * @param mixed $value
1448       * @param mixed $minValue
1449       * @param mixed $maxValue
1450       * @param string|callable|null $message
1451       * @param string|null $propertyPath
1452       *
1453       * @return bool
1454       *
1455       * @throws AssertionFailedException
1456       */
1457      public static function range($value, $minValue, $maxValue, $message = null, string $propertyPath = null): bool
1458      {
1459          static::numeric($value, $message, $propertyPath);
1460  
1461          if ($value < $minValue || $value > $maxValue) {
1462              $message = \sprintf(
1463                  static::generateMessage($message ?: 'Number "%s" was expected to be at least "%d" and at most "%d".'),
1464                  static::stringify($value),
1465                  static::stringify($minValue),
1466                  static::stringify($maxValue)
1467              );
1468  
1469              throw static::createException($value, $message, static::INVALID_RANGE, $propertyPath, ['min' => $minValue, 'max' => $maxValue]);
1470          }
1471  
1472          return true;
1473      }
1474  
1475      /**
1476       * Assert that a value is at least as big as a given limit.
1477       *
1478       * @param mixed $value
1479       * @param mixed $minValue
1480       * @param string|callable|null $message
1481       * @param string|null $propertyPath
1482       *
1483       * @return bool
1484       *
1485       * @throws AssertionFailedException
1486       */
1487      public static function min($value, $minValue, $message = null, string $propertyPath = null): bool
1488      {
1489          static::numeric($value, $message, $propertyPath);
1490  
1491          if ($value < $minValue) {
1492              $message = \sprintf(
1493                  static::generateMessage($message ?: 'Number "%s" was expected to be at least "%s".'),
1494                  static::stringify($value),
1495                  static::stringify($minValue)
1496              );
1497  
1498              throw static::createException($value, $message, static::INVALID_MIN, $propertyPath, ['min' => $minValue]);
1499          }
1500  
1501          return true;
1502      }
1503  
1504      /**
1505       * Assert that a number is smaller as a given limit.
1506       *
1507       * @param mixed $value
1508       * @param mixed $maxValue
1509       * @param string|callable|null $message
1510       * @param string|null $propertyPath
1511       *
1512       * @return bool
1513       *
1514       * @throws AssertionFailedException
1515       */
1516      public static function max($value, $maxValue, $message = null, string $propertyPath = null): bool
1517      {
1518          static::numeric($value, $message, $propertyPath);
1519  
1520          if ($value > $maxValue) {
1521              $message = \sprintf(
1522                  static::generateMessage($message ?: 'Number "%s" was expected to be at most "%s".'),
1523                  static::stringify($value),
1524                  static::stringify($maxValue)
1525              );
1526  
1527              throw static::createException($value, $message, static::INVALID_MAX, $propertyPath, ['max' => $maxValue]);
1528          }
1529  
1530          return true;
1531      }
1532  
1533      /**
1534       * Assert that a file exists.
1535       *
1536       * @param string $value
1537       * @param string|callable|null $message
1538       * @param string|null $propertyPath
1539       *
1540       * @return bool
1541       *
1542       * @throws AssertionFailedException
1543       */
1544      public static function file($value, $message = null, string $propertyPath = null): bool
1545      {
1546          static::string($value, $message, $propertyPath);
1547          static::notEmpty($value, $message, $propertyPath);
1548  
1549          if (!\is_file($value)) {
1550              $message = \sprintf(
1551                  static::generateMessage($message ?: 'File "%s" was expected to exist.'),
1552                  static::stringify($value)
1553              );
1554  
1555              throw static::createException($value, $message, static::INVALID_FILE, $propertyPath);
1556          }
1557  
1558          return true;
1559      }
1560  
1561      /**
1562       * Assert that a directory exists.
1563       *
1564       * @param string $value
1565       * @param string|callable|null $message
1566       * @param string|null $propertyPath
1567       *
1568       * @return bool
1569       *
1570       * @throws AssertionFailedException
1571       */
1572      public static function directory($value, $message = null, string $propertyPath = null): bool
1573      {
1574          static::string($value, $message, $propertyPath);
1575  
1576          if (!\is_dir($value)) {
1577              $message = \sprintf(
1578                  static::generateMessage($message ?: 'Path "%s" was expected to be a directory.'),
1579                  static::stringify($value)
1580              );
1581  
1582              throw static::createException($value, $message, static::INVALID_DIRECTORY, $propertyPath);
1583          }
1584  
1585          return true;
1586      }
1587  
1588      /**
1589       * Assert that the value is something readable.
1590       *
1591       * @param string $value
1592       * @param string|callable|null $message
1593       * @param string|null $propertyPath
1594       *
1595       * @return bool
1596       *
1597       * @throws AssertionFailedException
1598       */
1599      public static function readable($value, $message = null, string $propertyPath = null): bool
1600      {
1601          static::string($value, $message, $propertyPath);
1602  
1603          if (!\is_readable($value)) {
1604              $message = \sprintf(
1605                  static::generateMessage($message ?: 'Path "%s" was expected to be readable.'),
1606                  static::stringify($value)
1607              );
1608  
1609              throw static::createException($value, $message, static::INVALID_READABLE, $propertyPath);
1610          }
1611  
1612          return true;
1613      }
1614  
1615      /**
1616       * Assert that the value is something writeable.
1617       *
1618       * @param string $value
1619       * @param string|callable|null $message
1620       * @param string|null $propertyPath
1621       *
1622       * @return bool
1623       *
1624       * @throws AssertionFailedException
1625       */
1626      public static function writeable($value, $message = null, string $propertyPath = null): bool
1627      {
1628          static::string($value, $message, $propertyPath);
1629  
1630          if (!\is_writable($value)) {
1631              $message = \sprintf(
1632                  static::generateMessage($message ?: 'Path "%s" was expected to be writeable.'),
1633                  static::stringify($value)
1634              );
1635  
1636              throw static::createException($value, $message, static::INVALID_WRITEABLE, $propertyPath);
1637          }
1638  
1639          return true;
1640      }
1641  
1642      /**
1643       * Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL).
1644       *
1645       * @param mixed $value
1646       * @param string|callable|null $message
1647       * @param string|null $propertyPath
1648       *
1649       * @return bool
1650       *
1651       * @throws AssertionFailedException
1652       */
1653      public static function email($value, $message = null, string $propertyPath = null): bool
1654      {
1655          static::string($value, $message, $propertyPath);
1656  
1657          if (!\filter_var($value, FILTER_VALIDATE_EMAIL)) {
1658              $message = \sprintf(
1659                  static::generateMessage($message ?: 'Value "%s" was expected to be a valid e-mail address.'),
1660                  static::stringify($value)
1661              );
1662  
1663              throw static::createException($value, $message, static::INVALID_EMAIL, $propertyPath);
1664          }
1665  
1666          return true;
1667      }
1668  
1669      /**
1670       * Assert that value is an URL.
1671       *
1672       * This code snipped was taken from the Symfony project and modified to the special demands of this method.
1673       *
1674       * @param mixed $value
1675       * @param string|callable|null $message
1676       * @param string|null $propertyPath
1677       *
1678       * @return bool
1679       *
1680       * @throws AssertionFailedException
1681       *
1682       * @see https://github.com/symfony/Validator/blob/master/Constraints/UrlValidator.php
1683       * @see https://github.com/symfony/Validator/blob/master/Constraints/Url.php
1684       */
1685      public static function url($value, $message = null, string $propertyPath = null): bool
1686      {
1687          static::string($value, $message, $propertyPath);
1688  
1689          $protocols = ['http', 'https'];
1690  
1691          $pattern = '~^
1692              (%s)://                                                             # protocol
1693              (([\.\pL\pN-]+:)?([\.\pL\pN-]+)@)?                                  # basic auth
1694              (
1695                  ([\pL\pN\pS\-\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?)          # a domain name
1696                  |                                                               # or
1697                  \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}                              # an IP address
1698                  |                                                               # or
1699                  \[
1700                      (?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::))))
1701                  \]                                                              # an IPv6 address
1702              )
1703              (:[0-9]+)?                                                          # a port (optional)
1704              (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%%[0-9A-Fa-f]{2})* )*          # a path
1705              (?:\? (?:[\pL\pN\-._\~!$&\'\[\]()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )?   # a query (optional)
1706              (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )?       # a fragment (optional)
1707          $~ixu';
1708  
1709          $pattern = \sprintf($pattern, \implode('|', $protocols));
1710  
1711          if (!\preg_match($pattern, $value)) {
1712              $message = \sprintf(
1713                  static::generateMessage($message ?: 'Value "%s" was expected to be a valid URL starting with http or https'),
1714                  static::stringify($value)
1715              );
1716  
1717              throw static::createException($value, $message, static::INVALID_URL, $propertyPath);
1718          }
1719  
1720          return true;
1721      }
1722  
1723      /**
1724       * Assert that value is alphanumeric.
1725       *
1726       * @param mixed $value
1727       * @param string|callable|null $message
1728       * @param string|null $propertyPath
1729       *
1730       * @return bool
1731       *
1732       * @throws AssertionFailedException
1733       */
1734      public static function alnum($value, $message = null, string $propertyPath = null): bool
1735      {
1736          try {
1737              static::regex($value, '(^([a-zA-Z]{1}[a-zA-Z0-9]*)$)', $message, $propertyPath);
1738          } catch (Throwable $e) {
1739              $message = \sprintf(
1740                  static::generateMessage($message ?: 'Value "%s" is not alphanumeric, starting with letters and containing only letters and numbers.'),
1741                  static::stringify($value)
1742              );
1743  
1744              throw static::createException($value, $message, static::INVALID_ALNUM, $propertyPath);
1745          }
1746  
1747          return true;
1748      }
1749  
1750      /**
1751       * Assert that the value is boolean True.
1752       *
1753       * @param mixed $value
1754       * @param string|callable|null $message
1755       * @param string|null $propertyPath
1756       *
1757       * @return bool
1758       *
1759       * @throws AssertionFailedException
1760       */
1761      public static function true($value, $message = null, string $propertyPath = null): bool
1762      {
1763          if (true !== $value) {
1764              $message = \sprintf(
1765                  static::generateMessage($message ?: 'Value "%s" is not TRUE.'),
1766                  static::stringify($value)
1767              );
1768  
1769              throw static::createException($value, $message, static::INVALID_TRUE, $propertyPath);
1770          }
1771  
1772          return true;
1773      }
1774  
1775      /**
1776       * Assert that the value is boolean False.
1777       *
1778       * @param mixed $value
1779       * @param string|callable|null $message
1780       * @param string|null $propertyPath
1781       *
1782       * @return bool
1783       *
1784       * @throws AssertionFailedException
1785       */
1786      public static function false($value, $message = null, string $propertyPath = null): bool
1787      {
1788          if (false !== $value) {
1789              $message = \sprintf(
1790                  static::generateMessage($message ?: 'Value "%s" is not FALSE.'),
1791                  static::stringify($value)
1792              );
1793  
1794              throw static::createException($value, $message, static::INVALID_FALSE, $propertyPath);
1795          }
1796  
1797          return true;
1798      }
1799  
1800      /**
1801       * Assert that the class exists.
1802       *
1803       * @param mixed $value
1804       * @param string|callable|null $message
1805       * @param string|null $propertyPath
1806       *
1807       * @return bool
1808       *
1809       * @throws AssertionFailedException
1810       */
1811      public static function classExists($value, $message = null, string $propertyPath = null): bool
1812      {
1813          if (!\class_exists($value)) {
1814              $message = \sprintf(
1815                  static::generateMessage($message ?: 'Class "%s" does not exist.'),
1816                  static::stringify($value)
1817              );
1818  
1819              throw static::createException($value, $message, static::INVALID_CLASS, $propertyPath);
1820          }
1821  
1822          return true;
1823      }
1824  
1825      /**
1826       * Assert that the interface exists.
1827       *
1828       * @param mixed $value
1829       * @param string|callable|null $message
1830       * @param string|null $propertyPath
1831       *
1832       * @return bool
1833       *
1834       * @throws AssertionFailedException
1835       */
1836      public static function interfaceExists($value, $message = null, string $propertyPath = null): bool
1837      {
1838          if (!\interface_exists($value)) {
1839              $message = \sprintf(
1840                  static::generateMessage($message ?: 'Interface "%s" does not exist.'),
1841                  static::stringify($value)
1842              );
1843  
1844              throw static::createException($value, $message, static::INVALID_INTERFACE, $propertyPath);
1845          }
1846  
1847          return true;
1848      }
1849  
1850      /**
1851       * Assert that the class implements the interface.
1852       *
1853       * @param mixed $class
1854       * @param string $interfaceName
1855       * @param string|callable|null $message
1856       * @param string|null $propertyPath
1857       *
1858       * @return bool
1859       *
1860       * @throws AssertionFailedException
1861       */
1862      public static function implementsInterface($class, $interfaceName, $message = null, string $propertyPath = null): bool
1863      {
1864          try {
1865              $reflection = new ReflectionClass($class);
1866              if (!$reflection->implementsInterface($interfaceName)) {
1867                  $message = \sprintf(
1868                      static::generateMessage($message ?: 'Class "%s" does not implement interface "%s".'),
1869                      static::stringify($class),
1870                      static::stringify($interfaceName)
1871                  );
1872  
1873                  throw static::createException($class, $message, static::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]);
1874              }
1875          } catch (ReflectionException $e) {
1876              $message = \sprintf(
1877                  static::generateMessage($message ?: 'Class "%s" failed reflection.'),
1878                  static::stringify($class)
1879              );
1880              throw static::createException($class, $message, static::INTERFACE_NOT_IMPLEMENTED, $propertyPath, ['interface' => $interfaceName]);
1881          }
1882  
1883          return true;
1884      }
1885  
1886      /**
1887       * Assert that the given string is a valid json string.
1888       *
1889       * NOTICE:
1890       * Since this does a json_decode to determine its validity
1891       * you probably should consider, when using the variable
1892       * content afterwards, just to decode and check for yourself instead
1893       * of using this assertion.
1894       *
1895       * @param mixed $value
1896       * @param string|callable|null $message
1897       * @param string|null $propertyPath
1898       *
1899       * @return bool
1900       *
1901       * @throws AssertionFailedException
1902       */
1903      public static function isJsonString($value, $message = null, string $propertyPath = null): bool
1904      {
1905          if (null === \json_decode($value) && JSON_ERROR_NONE !== \json_last_error()) {
1906              $message = \sprintf(
1907                  static::generateMessage($message ?: 'Value "%s" is not a valid JSON string.'),
1908                  static::stringify($value)
1909              );
1910  
1911              throw static::createException($value, $message, static::INVALID_JSON_STRING, $propertyPath);
1912          }
1913  
1914          return true;
1915      }
1916  
1917      /**
1918       * Assert that the given string is a valid UUID.
1919       *
1920       * Uses code from {@link https://github.com/ramsey/uuid} that is MIT licensed.
1921       *
1922       * @param string $value
1923       * @param string|callable|null $message
1924       * @param string|null $propertyPath
1925       *
1926       * @return bool
1927       *
1928       * @throws AssertionFailedException
1929       */
1930      public static function uuid($value, $message = null, string $propertyPath = null): bool
1931      {
1932          $value = \str_replace(['urn:', 'uuid:', '{', '}'], '', $value);
1933  
1934          if ('00000000-0000-0000-0000-000000000000' === $value) {
1935              return true;
1936          }
1937  
1938          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)) {
1939              $message = \sprintf(
1940                  static::generateMessage($message ?: 'Value "%s" is not a valid UUID.'),
1941                  static::stringify($value)
1942              );
1943  
1944              throw static::createException($value, $message, static::INVALID_UUID, $propertyPath);
1945          }
1946  
1947          return true;
1948      }
1949  
1950      /**
1951       * Assert that the given string is a valid E164 Phone Number.
1952       *
1953       * @see https://en.wikipedia.org/wiki/E.164
1954       *
1955       * @param string $value
1956       * @param string|callable|null $message
1957       * @param string|null $propertyPath
1958       *
1959       * @return bool
1960       *
1961       * @throws AssertionFailedException
1962       */
1963      public static function e164($value, $message = null, string $propertyPath = null): bool
1964      {
1965          if (!\preg_match('/^\+?[1-9]\d{1,14}$/', $value)) {
1966              $message = \sprintf(
1967                  static::generateMessage($message ?: 'Value "%s" is not a valid E164.'),
1968                  static::stringify($value)
1969              );
1970  
1971              throw static::createException($value, $message, static::INVALID_E164, $propertyPath);
1972          }
1973  
1974          return true;
1975      }
1976  
1977      /**
1978       * Assert that the count of countable is equal to count.
1979       *
1980       * @param array|Countable|ResourceBundle|SimpleXMLElement $countable
1981       * @param int $count
1982       * @param string|callable|null $message
1983       * @param string|null $propertyPath
1984       *
1985       * @return bool
1986       *
1987       * @throws AssertionFailedException
1988       */
1989      public static function count($countable, $count, $message = null, string $propertyPath = null): bool
1990      {
1991          if ($count !== \count($countable)) {
1992              $message = \sprintf(
1993                  static::generateMessage($message ?: 'List does not contain exactly %d elements (%d given).'),
1994                  static::stringify($count),
1995                  static::stringify(\count($countable))
1996              );
1997  
1998              throw static::createException($countable, $message, static::INVALID_COUNT, $propertyPath, ['count' => $count]);
1999          }
2000  
2001          return true;
2002      }
2003  
2004      /**
2005       * Assert that the countable have at least $count elements.
2006       *
2007       * @param array|Countable|ResourceBundle|SimpleXMLElement $countable
2008       * @param int $count
2009       * @param string|callable|null $message
2010       * @param string|null $propertyPath
2011       *
2012       * @return bool
2013       *
2014       * @throws AssertionFailedException
2015       */
2016      public static function minCount($countable, $count, $message = null, string $propertyPath = null): bool
2017      {
2018          if ($count > \count($countable)) {
2019              $message = \sprintf(
2020                  static::generateMessage($message ?: 'List should have at least %d elements, but has %d elements.'),
2021                  static::stringify($count),
2022                  static::stringify(\count($countable))
2023              );
2024  
2025              throw static::createException($countable, $message, static::INVALID_MIN_COUNT, $propertyPath, ['count' => $count]);
2026          }
2027  
2028          return true;
2029      }
2030  
2031      /**
2032       * Assert that the countable have at most $count elements.
2033       *
2034       * @param array|Countable|ResourceBundle|SimpleXMLElement $countable
2035       * @param int $count
2036       * @param string|callable|null $message
2037       * @param string|null $propertyPath
2038       *
2039       * @return bool
2040       *
2041       * @throws AssertionFailedException
2042       */
2043      public static function maxCount($countable, $count, $message = null, string $propertyPath = null): bool
2044      {
2045          if ($count < \count($countable)) {
2046              $message = \sprintf(
2047                  static::generateMessage($message ?: 'List should have at most %d elements, but has %d elements.'),
2048                  static::stringify($count),
2049                  static::stringify(\count($countable))
2050              );
2051  
2052              throw static::createException($countable, $message, static::INVALID_MAX_COUNT, $propertyPath, ['count' => $count]);
2053          }
2054  
2055          return true;
2056      }
2057  
2058      /**
2059       * static call handler to implement:
2060       *  - "null or assertion" delegation
2061       *  - "all" delegation.
2062       *
2063       * @param string $method
2064       * @param array $args
2065       *
2066       * @return bool|mixed
2067       *
2068       * @throws AssertionFailedException
2069       */
2070      public static function __callStatic($method, $args)
2071      {
2072          if (0 === \strpos($method, 'nullOr')) {
2073              if (!\array_key_exists(0, $args)) {
2074                  throw new BadMethodCallException('Missing the first argument.');
2075              }
2076  
2077              if (null === $args[0]) {
2078                  return true;
2079              }
2080  
2081              $method = \substr($method, 6);
2082  
2083              return \call_user_func_array([\get_called_class(), $method], $args);
2084          }
2085  
2086          if (0 === \strpos($method, 'all')) {
2087              if (!\array_key_exists(0, $args)) {
2088                  throw new BadMethodCallException('Missing the first argument.');
2089              }
2090  
2091              static::isTraversable($args[0]);
2092  
2093              $method = \substr($method, 3);
2094              $values = \array_shift($args);
2095              $calledClass = \get_called_class();
2096  
2097              foreach ($values as $value) {
2098                  \call_user_func_array([$calledClass, $method], \array_merge([$value], $args));
2099              }
2100  
2101              return true;
2102          }
2103  
2104          throw new BadMethodCallException('No assertion Assertion#'.$method.' exists.');
2105      }
2106  
2107      /**
2108       * Determines if the values array has every choice as key and that this choice has content.
2109       *
2110       * @param array $values
2111       * @param array $choices
2112       * @param string|callable|null $message
2113       * @param string|null $propertyPath
2114       *
2115       * @return bool
2116       *
2117       * @throws AssertionFailedException
2118       */
2119      public static function choicesNotEmpty(array $values, array $choices, $message = null, string $propertyPath = null): bool
2120      {
2121          static::notEmpty($values, $message, $propertyPath);
2122  
2123          foreach ($choices as $choice) {
2124              static::notEmptyKey($values, $choice, $message, $propertyPath);
2125          }
2126  
2127          return true;
2128      }
2129  
2130      /**
2131       * Determines that the named method is defined in the provided object.
2132       *
2133       * @param string $value
2134       * @param mixed $object
2135       * @param string|callable|null $message
2136       * @param string|null $propertyPath
2137       *
2138       * @return bool
2139       *
2140       * @throws AssertionFailedException
2141       */
2142      public static function methodExists($value, $object, $message = null, string $propertyPath = null): bool
2143      {
2144          static::isObject($object, $message, $propertyPath);
2145  
2146          if (!\method_exists($object, $value)) {
2147              $message = \sprintf(
2148                  static::generateMessage($message ?: 'Expected "%s" does not exist in provided object.'),
2149                  static::stringify($value)
2150              );
2151  
2152              throw static::createException($value, $message, static::INVALID_METHOD, $propertyPath, ['object' => \get_class($object)]);
2153          }
2154  
2155          return true;
2156      }
2157  
2158      /**
2159       * Determines that the provided value is an object.
2160       *
2161       * @param mixed $value
2162       * @param string|callable|null $message
2163       * @param string|null $propertyPath
2164       *
2165       * @return bool
2166       *
2167       * @throws AssertionFailedException
2168       */
2169      public static function isObject($value, $message = null, string $propertyPath = null): bool
2170      {
2171          if (!\is_object($value)) {
2172              $message = \sprintf(
2173                  static::generateMessage($message ?: 'Provided "%s" is not a valid object.'),
2174                  static::stringify($value)
2175              );
2176  
2177              throw static::createException($value, $message, static::INVALID_OBJECT, $propertyPath);
2178          }
2179  
2180          return true;
2181      }
2182  
2183      /**
2184       * Determines if the value is less than given limit.
2185       *
2186       * @param mixed $value
2187       * @param mixed $limit
2188       * @param string|callable|null $message
2189       * @param string|null $propertyPath
2190       *
2191       * @return bool
2192       *
2193       * @throws AssertionFailedException
2194       */
2195      public static function lessThan($value, $limit, $message = null, string $propertyPath = null): bool
2196      {
2197          if ($value >= $limit) {
2198              $message = \sprintf(
2199                  static::generateMessage($message ?: 'Provided "%s" is not less than "%s".'),
2200                  static::stringify($value),
2201                  static::stringify($limit)
2202              );
2203  
2204              throw static::createException($value, $message, static::INVALID_LESS, $propertyPath, ['limit' => $limit]);
2205          }
2206  
2207          return true;
2208      }
2209  
2210      /**
2211       * Determines if the value is less or equal than given limit.
2212       *
2213       * @param mixed $value
2214       * @param mixed $limit
2215       * @param string|callable|null $message
2216       * @param string|null $propertyPath
2217       *
2218       * @return bool
2219       *
2220       * @throws AssertionFailedException
2221       */
2222      public static function lessOrEqualThan($value, $limit, $message = null, string $propertyPath = null): bool
2223      {
2224          if ($value > $limit) {
2225              $message = \sprintf(
2226                  static::generateMessage($message ?: 'Provided "%s" is not less or equal than "%s".'),
2227                  static::stringify($value),
2228                  static::stringify($limit)
2229              );
2230  
2231              throw static::createException($value, $message, static::INVALID_LESS_OR_EQUAL, $propertyPath, ['limit' => $limit]);
2232          }
2233  
2234          return true;
2235      }
2236  
2237      /**
2238       * Determines if the value is greater than given limit.
2239       *
2240       * @param mixed $value
2241       * @param mixed $limit
2242       * @param string|callable|null $message
2243       * @param string|null $propertyPath
2244       *
2245       * @return bool
2246       *
2247       * @throws AssertionFailedException
2248       */
2249      public static function greaterThan($value, $limit, $message = null, string $propertyPath = null): bool
2250      {
2251          if ($value <= $limit) {
2252              $message = \sprintf(
2253                  static::generateMessage($message ?: 'Provided "%s" is not greater than "%s".'),
2254                  static::stringify($value),
2255                  static::stringify($limit)
2256              );
2257  
2258              throw static::createException($value, $message, static::INVALID_GREATER, $propertyPath, ['limit' => $limit]);
2259          }
2260  
2261          return true;
2262      }
2263  
2264      /**
2265       * Determines if the value is greater or equal than given limit.
2266       *
2267       * @param mixed $value
2268       * @param mixed $limit
2269       * @param string|callable|null $message
2270       * @param string|null $propertyPath
2271       *
2272       * @return bool
2273       *
2274       * @throws AssertionFailedException
2275       */
2276      public static function greaterOrEqualThan($value, $limit, $message = null, string $propertyPath = null): bool
2277      {
2278          if ($value < $limit) {
2279              $message = \sprintf(
2280                  static::generateMessage($message ?: 'Provided "%s" is not greater or equal than "%s".'),
2281                  static::stringify($value),
2282                  static::stringify($limit)
2283              );
2284  
2285              throw static::createException($value, $message, static::INVALID_GREATER_OR_EQUAL, $propertyPath, ['limit' => $limit]);
2286          }
2287  
2288          return true;
2289      }
2290  
2291      /**
2292       * Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit.
2293       *
2294       * @param mixed $value
2295       * @param mixed $lowerLimit
2296       * @param mixed $upperLimit
2297       * @param string|callable|null $message
2298       * @param string $propertyPath
2299       *
2300       * @return bool
2301       *
2302       * @throws AssertionFailedException
2303       */
2304      public static function between($value, $lowerLimit, $upperLimit, $message = null, string $propertyPath = null): bool
2305      {
2306          if ($lowerLimit > $value || $value > $upperLimit) {
2307              $message = \sprintf(
2308                  static::generateMessage($message ?: 'Provided "%s" is neither greater than or equal to "%s" nor less than or equal to "%s".'),
2309                  static::stringify($value),
2310                  static::stringify($lowerLimit),
2311                  static::stringify($upperLimit)
2312              );
2313  
2314              throw static::createException($value, $message, static::INVALID_BETWEEN, $propertyPath, ['lower' => $lowerLimit, 'upper' => $upperLimit]);
2315          }
2316  
2317          return true;
2318      }
2319  
2320      /**
2321       * Assert that a value is greater than a lower limit, and less than an upper limit.
2322       *
2323       * @param mixed $value
2324       * @param mixed $lowerLimit
2325       * @param mixed $upperLimit
2326       * @param string|callable|null $message
2327       * @param string $propertyPath
2328       *
2329       * @return bool
2330       *
2331       * @throws AssertionFailedException
2332       */
2333      public static function betweenExclusive($value, $lowerLimit, $upperLimit, $message = null, string $propertyPath = null): bool
2334      {
2335          if ($lowerLimit >= $value || $value >= $upperLimit) {
2336              $message = \sprintf(
2337                  static::generateMessage($message ?: 'Provided "%s" is neither greater than "%s" nor less than "%s".'),
2338                  static::stringify($value),
2339                  static::stringify($lowerLimit),
2340                  static::stringify($upperLimit)
2341              );
2342  
2343              throw static::createException($value, $message, static::INVALID_BETWEEN_EXCLUSIVE, $propertyPath, ['lower' => $lowerLimit, 'upper' => $upperLimit]);
2344          }
2345  
2346          return true;
2347      }
2348  
2349      /**
2350       * Assert that extension is loaded.
2351       *
2352       * @param mixed $value
2353       * @param string|callable|null $message
2354       * @param string|null $propertyPath
2355       *
2356       * @return bool
2357       *
2358       * @throws AssertionFailedException
2359       */
2360      public static function extensionLoaded($value, $message = null, string $propertyPath = null): bool
2361      {
2362          if (!\extension_loaded($value)) {
2363              $message = \sprintf(
2364                  static::generateMessage($message ?: 'Extension "%s" is required.'),
2365                  static::stringify($value)
2366              );
2367  
2368              throw static::createException($value, $message, static::INVALID_EXTENSION, $propertyPath);
2369          }
2370  
2371          return true;
2372      }
2373  
2374      /**
2375       * Assert that date is valid and corresponds to the given format.
2376       *
2377       * @param string $value
2378       * @param string $format supports all of the options date(), except for the following:
2379       *                       N, w, W, t, L, o, B, a, A, g, h, I, O, P, Z, c, r
2380       * @param string|callable|null $message
2381       * @param string|null $propertyPath
2382       *
2383       * @return bool
2384       *
2385       * @throws AssertionFailedException
2386       *
2387       * @see http://php.net/manual/function.date.php#refsect1-function.date-parameters
2388       */
2389      public static function date($value, $format, $message = null, string $propertyPath = null): bool
2390      {
2391          static::string($value, $message, $propertyPath);
2392          static::string($format, $message, $propertyPath);
2393  
2394          $dateTime = DateTime::createFromFormat('!'.$format, $value);
2395  
2396          if (false === $dateTime || $value !== $dateTime->format($format)) {
2397              $message = \sprintf(
2398                  static::generateMessage($message ?: 'Date "%s" is invalid or does not match format "%s".'),
2399                  static::stringify($value),
2400                  static::stringify($format)
2401              );
2402  
2403              throw static::createException($value, $message, static::INVALID_DATE, $propertyPath, ['format' => $format]);
2404          }
2405  
2406          return true;
2407      }
2408  
2409      /**
2410       * Assert that the value is an object, or a class that exists.
2411       *
2412       * @param mixed $value
2413       * @param string|callable|null $message
2414       * @param string|null $propertyPath
2415       *
2416       * @return bool
2417       *
2418       * @throws AssertionFailedException
2419       */
2420      public static function objectOrClass($value, $message = null, string $propertyPath = null): bool
2421      {
2422          if (!\is_object($value)) {
2423              static::classExists($value, $message, $propertyPath);
2424          }
2425  
2426          return true;
2427      }
2428  
2429      /**
2430       * Assert that the value is an object or class, and that the property exists.
2431       *
2432       * @param mixed $value
2433       * @param string $property
2434       * @param string|callable|null $message
2435       * @param string|null $propertyPath
2436       *
2437       * @return bool
2438       *
2439       * @throws AssertionFailedException
2440       */
2441      public static function propertyExists($value, $property, $message = null, string $propertyPath = null): bool
2442      {
2443          static::objectOrClass($value);
2444  
2445          if (!\property_exists($value, $property)) {
2446              $message = \sprintf(
2447                  static::generateMessage($message ?: 'Class "%s" does not have property "%s".'),
2448                  static::stringify($value),
2449                  static::stringify($property)
2450              );
2451  
2452              throw static::createException($value, $message, static::INVALID_PROPERTY, $propertyPath, ['property' => $property]);
2453          }
2454  
2455          return true;
2456      }
2457  
2458      /**
2459       * Assert that the value is an object or class, and that the properties all exist.
2460       *
2461       * @param mixed $value
2462       * @param array $properties
2463       * @param string|callable|null $message
2464       * @param string|null $propertyPath
2465       *
2466       * @return bool
2467       *
2468       * @throws AssertionFailedException
2469       */
2470      public static function propertiesExist($value, array $properties, $message = null, string $propertyPath = null): bool
2471      {
2472          static::objectOrClass($value);
2473          static::allString($properties, $message, $propertyPath);
2474  
2475          $invalidProperties = [];
2476          foreach ($properties as $property) {
2477              if (!\property_exists($value, $property)) {
2478                  $invalidProperties[] = $property;
2479              }
2480          }
2481  
2482          if ($invalidProperties) {
2483              $message = \sprintf(
2484                  static::generateMessage($message ?: 'Class "%s" does not have these properties: %s.'),
2485                  static::stringify($value),
2486                  static::stringify(\implode(', ', $invalidProperties))
2487              );
2488  
2489              throw static::createException($value, $message, static::INVALID_PROPERTY, $propertyPath, ['properties' => $properties]);
2490          }
2491  
2492          return true;
2493      }
2494  
2495      /**
2496       * Assert comparison of two versions.
2497       *
2498       * @param string $version1
2499       * @param string $operator
2500       * @param string $version2
2501       * @param string|callable|null $message
2502       * @param string|null $propertyPath
2503       *
2504       * @return bool
2505       *
2506       * @throws AssertionFailedException
2507       */
2508      public static function version($version1, $operator, $version2, $message = null, string $propertyPath = null): bool
2509      {
2510          static::notEmpty($operator, 'versionCompare operator is required and cannot be empty.');
2511  
2512          if (true !== \version_compare($version1, $version2, $operator)) {
2513              $message = \sprintf(
2514                  static::generateMessage($message ?: 'Version "%s" is not "%s" version "%s".'),
2515                  static::stringify($version1),
2516                  static::stringify($operator),
2517                  static::stringify($version2)
2518              );
2519  
2520              throw static::createException($version1, $message, static::INVALID_VERSION, $propertyPath, ['operator' => $operator, 'version' => $version2]);
2521          }
2522  
2523          return true;
2524      }
2525  
2526      /**
2527       * Assert on PHP version.
2528       *
2529       * @param string $operator
2530       * @param mixed $version
2531       * @param string|callable|null $message
2532       * @param string|null $propertyPath
2533       *
2534       * @return bool
2535       *
2536       * @throws AssertionFailedException
2537       */
2538      public static function phpVersion($operator, $version, $message = null, string $propertyPath = null): bool
2539      {
2540          static::defined('PHP_VERSION');
2541  
2542          return static::version(PHP_VERSION, $operator, $version, $message, $propertyPath);
2543      }
2544  
2545      /**
2546       * Assert that extension is loaded and a specific version is installed.
2547       *
2548       * @param string $extension
2549       * @param string $operator
2550       * @param mixed $version
2551       * @param string|callable|null $message
2552       * @param string|null $propertyPath
2553       *
2554       * @return bool
2555       *
2556       * @throws AssertionFailedException
2557       */
2558      public static function extensionVersion($extension, $operator, $version, $message = null, string $propertyPath = null): bool
2559      {
2560          static::extensionLoaded($extension, $message, $propertyPath);
2561  
2562          return static::version(\phpversion($extension), $operator, $version, $message, $propertyPath);
2563      }
2564  
2565      /**
2566       * Determines that the provided value is callable.
2567       *
2568       * @param mixed $value
2569       * @param string|callable|null $message
2570       * @param string|null $propertyPath
2571       *
2572       * @return bool
2573       *
2574       * @throws AssertionFailedException
2575       */
2576      public static function isCallable($value, $message = null, string $propertyPath = null): bool
2577      {
2578          if (!\is_callable($value)) {
2579              $message = \sprintf(
2580                  static::generateMessage($message ?: 'Provided "%s" is not a callable.'),
2581                  static::stringify($value)
2582              );
2583  
2584              throw static::createException($value, $message, static::INVALID_CALLABLE, $propertyPath);
2585          }
2586  
2587          return true;
2588      }
2589  
2590      /**
2591       * Assert that the provided value is valid according to a callback.
2592       *
2593       * If the callback returns `false` the assertion will fail.
2594       *
2595       * @param mixed $value
2596       * @param callable $callback
2597       * @param string|callable|null $message
2598       * @param string|null $propertyPath
2599       *
2600       * @return bool
2601       *
2602       * @throws AssertionFailedException
2603       */
2604      public static function satisfy($value, $callback, $message = null, string $propertyPath = null): bool
2605      {
2606          static::isCallable($callback);
2607  
2608          if (false === \call_user_func($callback, $value)) {
2609              $message = \sprintf(
2610                  static::generateMessage($message ?: 'Provided "%s" is invalid according to custom rule.'),
2611                  static::stringify($value)
2612              );
2613  
2614              throw static::createException($value, $message, static::INVALID_SATISFY, $propertyPath);
2615          }
2616  
2617          return true;
2618      }
2619  
2620      /**
2621       * Assert that value is an IPv4 or IPv6 address
2622       * (using input_filter/FILTER_VALIDATE_IP).
2623       *
2624       * @param string $value
2625       * @param int|null $flag
2626       * @param string|callable|null $message
2627       * @param string|null $propertyPath
2628       *
2629       * @return bool
2630       *
2631       * @throws AssertionFailedException
2632       *
2633       * @see http://php.net/manual/filter.filters.flags.php
2634       */
2635      public static function ip($value, $flag = null, $message = null, string $propertyPath = null): bool
2636      {
2637          static::string($value, $message, $propertyPath);
2638          if (!\filter_var($value, FILTER_VALIDATE_IP, $flag)) {
2639              $message = \sprintf(
2640                  static::generateMessage($message ?: 'Value "%s" was expected to be a valid IP address.'),
2641                  static::stringify($value)
2642              );
2643              throw static::createException($value, $message, static::INVALID_IP, $propertyPath, ['flag' => $flag]);
2644          }
2645  
2646          return true;
2647      }
2648  
2649      /**
2650       * Assert that value is an IPv4 address
2651       * (using input_filter/FILTER_VALIDATE_IP).
2652       *
2653       * @param string $value
2654       * @param int|null $flag
2655       * @param string|callable|null $message
2656       * @param string|null $propertyPath
2657       *
2658       * @return bool
2659       *
2660       * @throws AssertionFailedException
2661       *
2662       * @see http://php.net/manual/filter.filters.flags.php
2663       */
2664      public static function ipv4($value, $flag = null, $message = null, string $propertyPath = null): bool
2665      {
2666          static::ip($value, $flag | FILTER_FLAG_IPV4, static::generateMessage($message ?: 'Value "%s" was expected to be a valid IPv4 address.'), $propertyPath);
2667  
2668          return true;
2669      }
2670  
2671      /**
2672       * Assert that value is an IPv6 address
2673       * (using input_filter/FILTER_VALIDATE_IP).
2674       *
2675       * @param string $value
2676       * @param int|null $flag
2677       * @param string|callable|null $message
2678       * @param string|null $propertyPath
2679       *
2680       * @return bool
2681       *
2682       * @throws AssertionFailedException
2683       *
2684       * @see http://php.net/manual/filter.filters.flags.php
2685       */
2686      public static function ipv6($value, $flag = null, $message = null, string $propertyPath = null): bool
2687      {
2688          static::ip($value, $flag | FILTER_FLAG_IPV6, static::generateMessage($message ?: 'Value "%s" was expected to be a valid IPv6 address.'), $propertyPath);
2689  
2690          return true;
2691      }
2692  
2693      /**
2694       * Assert that a constant is defined.
2695       *
2696       * @param mixed $constant
2697       * @param string|callable|null $message
2698       * @param string|null $propertyPath
2699       *
2700       * @return bool
2701       */
2702      public static function defined($constant, $message = null, string $propertyPath = null): bool
2703      {
2704          if (!\defined($constant)) {
2705              $message = \sprintf(static::generateMessage($message ?: 'Value "%s" expected to be a defined constant.'), $constant);
2706  
2707              throw static::createException($constant, $message, static::INVALID_CONSTANT, $propertyPath);
2708          }
2709  
2710          return true;
2711      }
2712  
2713      /**
2714       * Assert that a constant is defined.
2715       *
2716       * @param string $value
2717       * @param string|callable|null $message
2718       * @param string|null $propertyPath
2719       *
2720       * @return bool
2721       *
2722       * @throws AssertionFailedException
2723       */
2724      public static function base64($value, $message = null, string $propertyPath = null): bool
2725      {
2726          if (false === \base64_decode($value, true)) {
2727              $message = \sprintf(static::generateMessage($message ?: 'Value "%s" is not a valid base64 string.'), $value);
2728  
2729              throw static::createException($value, $message, static::INVALID_BASE64, $propertyPath);
2730          }
2731  
2732          return true;
2733      }
2734  
2735      /**
2736       * Helper method that handles building the assertion failure exceptions.
2737       * They are returned from this method so that the stack trace still shows
2738       * the assertions method.
2739       *
2740       * @param mixed $value
2741       * @param string|callable|null $message
2742       * @param int $code
2743       * @param string|null $propertyPath
2744       * @param array $constraints
2745       *
2746       * @return mixed
2747       */
2748      protected static function createException($value, $message, $code, string $propertyPath = null, array $constraints = [])
2749      {
2750          $exceptionClass = static::$exceptionClass;
2751  
2752          return new $exceptionClass($message, $code, $propertyPath, $value, $constraints);
2753      }
2754  
2755      /**
2756       * Make a string version of a value.
2757       *
2758       * @param mixed $value
2759       *
2760       * @return string
2761       */
2762      protected static function stringify($value): string
2763      {
2764          $result = \gettype($value);
2765  
2766          if (\is_bool($value)) {
2767              $result = $value ? '<TRUE>' : '<FALSE>';
2768          } elseif (\is_scalar($value)) {
2769              $val = (string)$value;
2770  
2771              if (\strlen($val) > 100) {
2772                  $val = \substr($val, 0, 97).'...';
2773              }
2774  
2775              $result = $val;
2776          } elseif (\is_array($value)) {
2777              $result = '<ARRAY>';
2778          } elseif (\is_object($value)) {
2779              $result = \get_class($value);
2780          } elseif (\is_resource($value)) {
2781              $result = \get_resource_type($value);
2782          } elseif (null === $value) {
2783              $result = '<NULL>';
2784          }
2785  
2786          return $result;
2787      }
2788  
2789      /**
2790       * Generate the message.
2791       *
2792       * @param string|callable|null $message
2793       *
2794       * @return string
2795       */
2796      protected static function generateMessage($message): string
2797      {
2798          if (\is_callable($message)) {
2799              $traces = \debug_backtrace(0);
2800  
2801              $parameters = [];
2802  
2803              try {
2804                  $reflection = new ReflectionClass($traces[1]['class']);
2805                  $method = $reflection->getMethod($traces[1]['function']);
2806                  foreach ($method->getParameters() as $index => $parameter) {
2807                      if ('message' !== $parameter->getName()) {
2808                          $parameters[$parameter->getName()] = \array_key_exists($index, $traces[1]['args'])
2809                              ? $traces[1]['args'][$index]
2810                              : $parameter->getDefaultValue();
2811                      }
2812                  }
2813  
2814                  $parameters['::assertion'] = \sprintf('%s%s%s', $traces[1]['class'], $traces[1]['type'], $traces[1]['function']);
2815  
2816                  $message = \call_user_func_array($message, [$parameters]);
2817              } // @codeCoverageIgnoreStart
2818              catch (Throwable $exception) {
2819                  $message = \sprintf('Unable to generate message : %s', $exception->getMessage());
2820              } // @codeCoverageIgnoreEnd
2821          }
2822  
2823          return (string)$message;
2824      }
2825  }