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