1: <?php declare(strict_types=1);
2:
3: namespace Salient\Utility;
4:
5: use Stringable;
6:
7: /**
8: * Perform tests on values
9: *
10: * @api
11: */
12: final class Test extends AbstractUtility
13: {
14: /**
15: * Check if a value is a boolean or boolean string
16: *
17: * @param mixed $value
18: * @phpstan-assert-if-true bool|non-empty-string $value
19: */
20: public static function isBoolean($value): bool
21: {
22: return is_bool($value) || (
23: is_string($value)
24: && Regex::match('/^' . Regex::BOOLEAN_STRING . '$/', trim($value))
25: );
26: }
27:
28: /**
29: * Check if a value is an integer or integer string
30: *
31: * @param mixed $value
32: * @phpstan-assert-if-true int|non-empty-string $value
33: */
34: public static function isInteger($value): bool
35: {
36: return is_int($value) || (
37: is_string($value)
38: && Regex::match('/^' . Regex::INTEGER_STRING . '$/', trim($value))
39: );
40: }
41:
42: /**
43: * Check if a value is a float or float string
44: *
45: * Returns `false` if `$value` is an integer string.
46: *
47: * @param mixed $value
48: * @phpstan-assert-if-true float|non-empty-string $value
49: */
50: public static function isFloat($value): bool
51: {
52: return is_float($value) || (
53: is_string($value)
54: && is_numeric($value = trim($value))
55: && !Regex::match('/^' . Regex::INTEGER_STRING . '$/', $value)
56: );
57: }
58:
59: /**
60: * Check if a value is an integer or would be cast to an integer if used as
61: * an array key
62: *
63: * @param mixed $value
64: * @phpstan-assert-if-true int|float|bool|non-empty-string $value
65: */
66: public static function isNumericKey($value): bool
67: {
68: return is_int($value)
69: || is_float($value)
70: || is_bool($value)
71: || (is_string($value) && Regex::match('/^(-?[1-9][0-9]*|0)$/D', $value));
72: }
73:
74: /**
75: * Check if a value is a valid date string
76: *
77: * @param mixed $value
78: * @phpstan-assert-if-true non-empty-string $value
79: */
80: public static function isDateString($value): bool
81: {
82: return is_string($value) && strtotime($value) !== false;
83: }
84:
85: /**
86: * Check if a value is a string or Stringable
87: *
88: * @param mixed $value
89: * @phpstan-assert-if-true Stringable|string $value
90: */
91: public static function isStringable($value): bool
92: {
93: return is_string($value)
94: || $value instanceof Stringable
95: || (is_object($value) && method_exists($value, '__toString'));
96: }
97:
98: /**
99: * Check if a value is a number within a range
100: *
101: * @param int|float $value
102: * @param int|float $min
103: * @param int|float $max
104: */
105: public static function isBetween($value, $min, $max): bool
106: {
107: return $value >= $min && $value <= $max;
108: }
109:
110: /**
111: * Check if a string is a built-in type
112: *
113: * @link https://www.php.net/manual/en/reserved.php
114: *
115: * @param bool $orRelativeClass If `true`, treat `"parent"`, `"self"` and
116: * `"static"` as built-in types.
117: * @param bool $orResource If `true`, treat `"resource"` as a built-in type.
118: */
119: public static function isBuiltinType(
120: string $value,
121: bool $orRelativeClass = true,
122: bool $orResource = true
123: ): bool {
124: // Types for which `ReflectionNamedType::isBuiltin()` returns `true`
125: $builtin = [
126: 'array' => true,
127: 'bool' => true,
128: 'callable' => true,
129: 'false' => true, // PHP 8.2+ (PHP 8.0+ in union types)
130: 'float' => true,
131: 'int' => true,
132: 'iterable' => true,
133: 'mixed' => true, // PHP 8.0+
134: 'never' => true, // PHP 8.1+
135: 'null' => true, // PHP 8.2+
136: 'object' => true,
137: 'string' => true,
138: 'true' => true, // PHP 8.2+
139: 'void' => true,
140: ];
141: !$orRelativeClass || $builtin += [
142: 'parent' => true,
143: 'self' => true,
144: 'static' => true,
145: ];
146: !$orResource || $builtin += [
147: 'resource' => true,
148: ];
149: return $builtin[Str::lower($value)] ?? false;
150: }
151:
152: /**
153: * Check if a value is a valid PHP class name
154: *
155: * @param mixed $value
156: * @phpstan-assert-if-true class-string $value
157: */
158: public static function isFqcn($value): bool
159: {
160: return is_string($value)
161: && Regex::match('/^' . Regex::PHP_TYPE . '$/D', $value);
162: }
163: }
164: