├── LICENSE ├── README.md ├── benchmark.sh ├── composer.json ├── phpbench.json ├── src ├── DataTypeValidator.php ├── InvalidDataTypeException.php ├── IsA.php ├── IsADataType.php ├── IsAFuzzyDataType.php └── IsAStrictDataType.php └── test.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2019-2025 PHP Experts, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DataTypeValidator 2 | 3 | [![TravisCI](https://travis-ci.org/phpexpertsinc/DataTypeValidator.svg?branch=master)](https://travis-ci.org/phpexpertsinc/DataTypeValidator) 4 | [![Maintainability](https://api.codeclimate.com/v1/badges/5d56aa8b847dce751598/maintainability)](https://codeclimate.com/github/phpexpertsinc/DataTypeValidator/maintainability) 5 | [![Test Coverage](https://api.codeclimate.com/v1/badges/5d56aa8b847dce751598/test_coverage)](https://codeclimate.com/github/phpexpertsinc/DataTypeValidator/test_coverage) 6 | 7 | DataTypeValidator is a PHP Experts, Inc., Project designed for easy data type validation. 8 | 9 | It supports both traditional, fuzzy, PHP data types (e.g., "1.0" can be both a float, int, and string) 10 | and strict data type validations ('1' is only a string, 1.0 is only a float, etc.). 11 | 12 | ## Installation 13 | 14 | Via Composer 15 | 16 | ```bash 17 | composer require phpexperts/datatype-validator 18 | ``` 19 | 20 | ## Upgrading to v3: 21 | 22 | As of v3.0, extra values not in the ruleset are explicitly asserted against when operating 23 | in strict mode. To upgrade, either use the `$this->isStrictMode()` to ensure you don't have 24 | extra inputs, or use the Fuzzy validator. 25 | 26 | ## Usage 27 | 28 | ```php 29 | // 1. Pick a Type Checker (IsAFuzzyDataType or IsAStrictDataType). 30 | // * IsAFuzzyDataType tries its best to emulate PHP's `==`. 31 | // * IsAStrictDataType observes PHP's `strict_types=1` rules. 32 | $validator = new DataValidator(new IsAStrictDataType()); 33 | 34 | // There are two powerful mechanisms out of the box: 35 | // 2. It is easy to validate any data type dynamically, without a ton of if statements. 36 | 37 | $validator->isType('asdf', 'string'); // true or false. 38 | $validator->assertIsType(1, 'int'); // null or throws InvalidDataTypeException 39 | 40 | // 3. You can also validate arrays: 41 | 42 | $data = [ 43 | 'name' => 'Cheyenne', 44 | 'age' => 22, 45 | 'birthday' => Carbon::parse('1996-12-04 15:15:15'), 46 | 'daysOld' => 8194.35, 47 | 'today' => Carbon::now(), 48 | 'sayHi' => function () { return 'Hi!'; }, 49 | ]; 50 | 51 | $rules = [ 52 | 'name' => 'string', 53 | 'age' => 'int', 54 | 'birthday' => 'Carbon', 55 | 'daysOld' => 'float', 56 | 'today' => 'Carbon\Carbon', 57 | 'sayHi' => 'callable', 58 | ]; 59 | 60 | $validator->validate($data, $rules); 61 | 62 | // 4. DataValidator::validate() will return `true` on success or throw 63 | // an `InvalidDataTypeException` that contains an array of errors: 64 | 65 | $data = [ 66 | 'name' => 'Cheyenne', 67 | 'age' => '22', 68 | 'birthday' => '1996-12-04 15:15:15', 69 | ]; 70 | 71 | try { 72 | $validator->validate($data, $rules); 73 | } catch (InvalidDataTypeException $e) { 74 | print_r($e->getReasons()); 75 | 76 | /* Output: 77 | array:2 [ 78 | 0 => "age is not a valid int" 79 | 1 => "birthday is not a valid Carbon" 80 | ] 81 | */ 82 | } 83 | 84 | // 5. It can validate objects based on their short name or full name. 85 | $data = [ 86 | 'yesterday' => \Carbon\Carbon::parse('2019-05-11'), 87 | 'tomorrow' => \Carbon\Carbon::parse('2019-05-13'), 88 | ]; 89 | 90 | $validator->validate($data, [ 91 | 'yesterday' => '\Carbon\Carbon', 92 | 'tomorrow' => 'Carbon', 93 | ]); 94 | 95 | ``` 96 | 97 | ## Benchmarks 98 | ```bash 99 | phpbench run --report=aggregate 100 | ``` 101 | 102 | PHP v8.4 with opcache enabled 103 | +------------------------+----------------+------+-----------+---------+---------+---------+---------+---------+--------+---------+ 104 | | benchmark | subject | revs | mem_peak | best | mean | mode | worst | stdev | rstdev | diff | 105 | +------------------------+----------------+------+-----------+---------+---------+---------+---------+---------+--------+---------+ 106 | | DataTypeValidatorBench | benchValidator | 1000 | 832.896kb | 4.414μs | 4.803μs | 4.876μs | 5.112μs | 0.233μs | ±4.85% | +2.57% | 107 | | DataTypeValidatorBench | benchNative | 1000 | 832.896kb | 2.670μs | 2.866μs | 2.745μs | 3.356μs | 0.250μs | ±8.71% | -42.25% | 108 | +------------------------+----------------+------+-----------+---------+---------+---------+---------+---------+--------+---------+ 109 | 110 | 111 | # Use cases 112 | 113 | PHPExperts\DataTypeValidator\DataTypeValidator 114 | ✔ Will report whether a strict or permissive validator is being used 115 | ✔ Can bulk validate a data array 116 | ✔ Will return the name of the data validator logic 117 | ✔ Will return an array of invalid keys with explanations 118 | ✔ Will silently ignore data not in the rules in permissive mode 119 | ✔ Will explicitly fail when data is not in the rules in strict mode 120 | ✔ Will silently ignore nullable rules with no data 121 | ✔ Data cannot be null by default 122 | ✔ Any data type that starts with a '?' is nullable 123 | ✔ Any data type that ends with '[]' is an array of X 124 | ✔ Will allow an empty array of something 125 | ✔ Will allow a nullable array of something 126 | ✔ Will throw a logic exception if a non string rule is given 127 | 128 | PHPExperts\DataTypeValidator\DataTypeValidator: Assertions 129 | ✔ Will assert a value is a bool 130 | ✔ Will assert a value is an int 131 | ✔ Will assert a value is a float 132 | ✔ Will assert a value is a string 133 | ✔ Will assert a value is an array 134 | ✔ Will assert a value is an object 135 | ✔ Will assert a value is a callable 136 | ✔ Will assert a value is a resource 137 | ✔ Will assert an array of something 138 | ✔ Will assert an object by its short name 139 | ✔ Will assert an object by its full name 140 | 141 | PHPExperts\DataTypeValidator\DataTypeValidator: Data Type Checks 142 | ✔ Will validate bools strictly 143 | ✔ Will validate ints strictly 144 | ✔ Will validate floats strictly 145 | ✔ Will validate strings strictly 146 | ✔ Will validate arrays strictly 147 | ✔ Will validate objects 148 | ✔ Will validate callables 149 | ✔ Will validate resources 150 | ✔ Will validate objects by their short name 151 | ✔ Will validate objects by their full name 152 | ✔ Can validate bools loosely 153 | ✔ Can validate ints loosely 154 | ✔ Can validate floats loosely 155 | ✔ Can validate strings loosely 156 | ✔ Can validate arrays loosely 157 | ✔ Will validate arrays of something 158 | ✔ Will validate anything as mixed type 159 | 160 | PHPExperts\DataTypeValidator\IsAFuzzyDataType 161 | ✔ Will say that it is a permissive validator 162 | ✔ Will return true for valid values 163 | ✔ Will return false for invalid values 164 | ✔ Will match short classes 165 | ✔ Will match specific classes 166 | ✔ Will work with an array of something 167 | 168 | PHPExperts\DataTypeValidator\IsAStrictDataType 169 | ✔ Will say that it is a strict validator 170 | ✔ Will return true for valid values 171 | ✔ Will return false for invalid values 172 | ✔ Will match short classes 173 | ✔ Will match specific classes 174 | ✔ Will work with an array of something 175 | 176 | Extended assertIsAType Tests 177 | ✔ has extended tests for asserting it is a strict string 178 | ✔ has extended tests for asserting it is a strict int 179 | ✔ has extended tests for asserting it is a strict bool 180 | ✔ has extended tests for asserting it is a strict array 181 | ✔ has extended tests for asserting it is a strict specific object 182 | ✔ has extended tests for asserting it is a fuzzy string 183 | ✔ has extended tests for asserting it is a fuzzy int 184 | ✔ has extended tests for asserting it is a fuzzy bool 185 | ✔ has extended tests for asserting it is a fuzzy array 186 | ✔ has extended tests for asserting it is a fuzzy object 187 | ✔ has extended tests for asserting it is a fuzzy specific object 188 | ✔ has extended tests for asserting it is not a strict string 189 | ✔ has extended tests for asserting it is not a strict int 190 | ✔ has extended tests for asserting it is not a strict bool 191 | ✔ has extended tests for asserting it is not a strict array 192 | ✔ has extended tests for asserting it is not a strict specific object 193 | ✔ has extended tests for asserting it is not a fuzzy string 194 | ✔ has extended tests for asserting it is not a fuzzy int 195 | ✔ has extended tests for asserting it is not a fuzzy bool 196 | ✔ has extended tests for asserting it is not a fuzzy array 197 | ✔ has extended tests for asserting it is not a fuzzy object 198 | ✔ has extended tests for asserting it is not a fuzzy specific object 199 | ✔ has extended tests for asserting it is a mixed type 200 | 201 | ## Testing 202 | 203 | ```bash 204 | phpunit 205 | ``` 206 | 207 | # Contributors 208 | 209 | [Theodore R. Smith](https://www.phpexperts.pro/]) 210 | GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690 211 | CEO: PHP Experts, Inc. 212 | 213 | ## License 214 | 215 | MIT license. Please see the [license file](LICENSE) for more information. 216 | 217 | -------------------------------------------------------------------------------- /benchmark.sh: -------------------------------------------------------------------------------- 1 | PHP_VERSION=8.4 composer update > /dev/null 2 | PHP_VERSION=8.4 php vendor/bin/phpbench run tests/Benchmark/ --report=short 3 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpexperts/datatype-validator", 3 | "type": "library", 4 | "description": "An easy to use data type validator (both strict and fuzzy).", 5 | "keywords": [ 6 | "datatype validator", 7 | "data type validator", 8 | "datatype", 9 | "data type", 10 | "validator", 11 | "validation" 12 | ], 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "PHP Experts, Inc.", 17 | "homepage": "https://www.phpexperts.pro/" 18 | }, 19 | { 20 | "name": "Theodore R. Smith", 21 | "homepage": "https://www.linkedin.com/in/tedrsmith" 22 | } 23 | ], 24 | "require": { 25 | "php": ">=8.0", 26 | "ext-json": "*" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "9.*", 30 | "symfony/var-dumper": "*", 31 | "phpstan/phpstan": "*", 32 | "nesbot/carbon": "^2.37", 33 | "phpbench/phpbench": "*", 34 | "phpexperts/dockerize": "^12.0" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "PHPExperts\\DataTypeValidator\\": "src/" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "PHPExperts\\DataTypeValidator\\Tests\\": "tests/" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /phpbench.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./vendor/phpbench/phpbench/phpbench.schema.json", 3 | "runner.bootstrap": "vendor/autoload.php", 4 | "runner.php_config": 5 | { 6 | "opcache.enable": 1, 7 | "opcache.enable_cli": 1 8 | }, 9 | "report.generators": 10 | { 11 | "short": 12 | { 13 | "extends": "aggregate", 14 | "cols": [ 15 | "benchmark", "subject", "revs", "mem_peak", 16 | "best", "mean", "mode", "worst", 17 | "stdev", "rstdev", 18 | "diff" 19 | ], 20 | "expressions": 21 | { 22 | "diff": "percent_diff(mode(suite[\"result_time_avg\"]), mode(result_time_avg))" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/DataTypeValidator.php: -------------------------------------------------------------------------------- 1 | 8 | * GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690 9 | * https://www.phpexperts.pro/ 10 | * https://github.com/phpexpertsinc/DataTypeValidator 11 | * 12 | * This file is licensed under the MIT License. 13 | */ 14 | 15 | namespace PHPExperts\DataTypeValidator; 16 | 17 | use LogicException; 18 | 19 | final class DataTypeValidator implements IsA 20 | { 21 | public function __construct(private IsADataType $isA) 22 | { 23 | } 24 | 25 | public function isStrictValidator(): bool 26 | { 27 | return $this->isA->isStrictValidator(); 28 | } 29 | 30 | public function getValidationType(): string 31 | { 32 | return $this->isA::class; 33 | } 34 | 35 | public function isBool(mixed $value): bool 36 | { 37 | return $this->isA->isBool($value); 38 | } 39 | 40 | public function isInt(mixed $value): bool 41 | { 42 | return $this->isA->isInt($value); 43 | } 44 | 45 | public function isFloat(mixed $value): bool 46 | { 47 | return $this->isA->isFloat($value); 48 | } 49 | 50 | public function isString(mixed $value): bool 51 | { 52 | return $this->isA->isString($value); 53 | } 54 | 55 | public function isArray(mixed $value): bool 56 | { 57 | return $this->isA->isArray($value); 58 | } 59 | 60 | public function isArrayOfSomething(mixed $values, string $dataType): bool 61 | { 62 | return $this->isA->isArrayOfSomething($values, $dataType); 63 | } 64 | 65 | public function isObject(mixed $value): bool 66 | { 67 | return $this->isA->isObject($value); 68 | } 69 | 70 | public function isCallable(mixed $value): bool 71 | { 72 | return $this->isA->isCallable($value); 73 | } 74 | 75 | public function isResource(mixed $value): bool 76 | { 77 | return $this->isA->isResource($value); 78 | } 79 | 80 | public function isFuzzyObject(mixed $value, string $shortName): bool 81 | { 82 | return $this->isA->isFuzzyObject($value, $shortName); 83 | } 84 | 85 | public function isSpecificObject(mixed $value, string $fullName): bool 86 | { 87 | return $this->isA->isSpecificObject($value, $fullName); 88 | } 89 | 90 | public function isMixed($value): bool 91 | { 92 | return $this->isA->isMixed($value); 93 | } 94 | 95 | /** @throws InvalidDataTypeException */ 96 | public function assertIsBool(mixed $value): void 97 | { 98 | $this->assertIsType($value, 'bool'); 99 | } 100 | 101 | /** @throws InvalidDataTypeException */ 102 | public function assertIsInt(mixed $value): void 103 | { 104 | $this->assertIsType($value, 'int'); 105 | } 106 | 107 | /** @throws InvalidDataTypeException */ 108 | public function assertIsFloat(mixed $value): void 109 | { 110 | $this->assertIsType($value, 'float'); 111 | } 112 | 113 | /** @throws InvalidDataTypeException */ 114 | public function assertIsString(mixed $value): void 115 | { 116 | $this->assertIsType($value, 'string'); 117 | } 118 | 119 | /** @throws InvalidDataTypeException */ 120 | public function assertIsArray(mixed $value): void 121 | { 122 | $this->assertIsType($value, 'array'); 123 | } 124 | 125 | /** @throws InvalidDataTypeException */ 126 | public function assertIsObject(mixed $value): void 127 | { 128 | $this->assertIsType($value, 'object'); 129 | } 130 | 131 | /** @throws InvalidDataTypeException */ 132 | public function assertIsCallable(mixed $value): void 133 | { 134 | $this->assertIsType($value, 'callable'); 135 | } 136 | 137 | /** @throws InvalidDataTypeException */ 138 | public function assertIsResource(mixed $value): void 139 | { 140 | $this->assertIsType($value, 'resource'); 141 | } 142 | 143 | /** @throws InvalidDataTypeException */ 144 | public function assertIsSpecificObject(mixed $value, string $className): void 145 | { 146 | $this->assertIsType($value, $className); 147 | } 148 | 149 | public function assertIsArrayOfSomething(mixed $values, string $dataType): void 150 | { 151 | $this->assertIsArray($values); 152 | 153 | $dataType = str_ends_with($dataType, '[]') ? substr($dataType, 0, -2) : $dataType; 154 | foreach ($values as $i => $value) { 155 | if (!$this->isA->isType($value, $dataType)) { 156 | throw new InvalidDataTypeException("Index '$i' is not a valid '$dataType'."); 157 | } 158 | } 159 | } 160 | 161 | /** @throws InvalidDataTypeException */ 162 | public function assertIsType(mixed $value, string $dataType): void 163 | { 164 | if ($dataType === 'mixed') { 165 | return; 166 | } 167 | 168 | // We can just let PHP deal with user error when it comes to undefined method names :-/ 169 | $isA = "is{$dataType}"; 170 | 171 | if (!in_array($dataType, IsA::KNOWN_TYPES)) { 172 | $isA = str_contains($dataType, '\\') ? 'isSpecificObject' : 'isFuzzyObject'; 173 | } 174 | 175 | // Thank you, PHP devs, for letting me throw on extra function parameters without even throwing a warning. /no-sarc 176 | if ($this->isA->$isA($value, $dataType) !== true) { 177 | $aAn = in_array($dataType[0], ['a', 'e', 'i', 'o', 'u']) ? 'an' : 'a'; 178 | // Handle data types that cannot be converted to strings. 179 | if (!in_array(gettype($value), ['string', 'int', 'float', 'double'])) { 180 | $value = substr((string) json_encode($value), 0, 15); 181 | } 182 | 183 | throw new InvalidDataTypeException("'$value' is not $aAn $dataType."); 184 | } 185 | } 186 | 187 | /** 188 | * Validates an array of values for the proper types; Laravel-esque. 189 | * 190 | * @param array $values 191 | * @param array $rules 192 | * @return bool 193 | * @throws InvalidDataTypeException 194 | */ 195 | public function validate(array $values, array $rules): bool 196 | { 197 | $reasons = []; 198 | 199 | // Check for extra properties not defined in rules. 200 | if ($this->isStrictValidator() === true) { 201 | foreach ($values as $key => $value) { 202 | if (!isset($rules[$key])) { 203 | $reasons[$key] = "'$key' is not a configured DTO property"; 204 | } 205 | } 206 | } 207 | 208 | foreach ($rules as $key => $expectedType) { 209 | if (!$this->isString($expectedType)) { 210 | throw new LogicException("The data type for $key is not a string."); 211 | } 212 | 213 | // Handle arrays-of-something. 214 | if (str_contains($expectedType, '[]')) { 215 | try { 216 | $this->validateArraysOfSomething($values[$key] ?? null, $expectedType); 217 | } catch (InvalidDataTypeException $e) { 218 | $reasons[$key] = "$key is not a valid array of $expectedType: " . $e->getMessage(); 219 | } 220 | continue; 221 | } 222 | 223 | try { 224 | $this->validateValue($values[$key] ?? null, $expectedType); 225 | } catch (InvalidDataTypeException) { 226 | $expectedType = $this->extractNullableProperty($expectedType); 227 | $reasons[$key] = "$key is not a valid $expectedType"; 228 | } 229 | } 230 | 231 | if (!empty($reasons)) { 232 | $count = count($reasons); 233 | $s = $count > 1 ? 's' : ''; 234 | $wasWere = $count > 1 ? 'were' : 'was'; 235 | throw new InvalidDataTypeException("There $wasWere $count validation error{$s}.", $reasons); 236 | } 237 | 238 | return true; 239 | } 240 | 241 | private function validateValue(mixed $value, string $expectedType): void 242 | { 243 | // Allow nullable types. 244 | $nullableType = $this->extractNullableProperty($expectedType); 245 | if ($nullableType !== $expectedType) { 246 | if ($value === null) { 247 | return; 248 | } 249 | 250 | $expectedType = $nullableType; 251 | } 252 | 253 | // Traditional values. 254 | if (in_array($expectedType, IsA::KNOWN_TYPES)) { 255 | $this->assertIsType($value, $expectedType); 256 | return; 257 | } 258 | 259 | // See if it is a specific class: 260 | $this->assertIsSpecificObject($value, $expectedType); 261 | } 262 | 263 | private function validateArraysOfSomething(mixed $values, string $expectedType): void 264 | { 265 | // Allow nullable types. 266 | $nullableType = $this->extractNullableProperty($expectedType); 267 | if ($nullableType !== $expectedType) { 268 | // If the data type is nullable and the value is null, let's bail early. 269 | if ($values === null) { 270 | return; 271 | } 272 | 273 | $expectedType = $nullableType; 274 | } 275 | 276 | $this->assertIsArrayOfSomething($values, substr($expectedType, 0, -2)); 277 | } 278 | 279 | private function extractNullableProperty(string $expectedType): string 280 | { 281 | if ($expectedType[0] === '?' || str_starts_with($expectedType, 'null|')) { 282 | $nullTokenPos = $expectedType[0] === '?' ? 1 : 5; 283 | 284 | // Then strip it out of the expected type. 285 | $expectedType = substr($expectedType, $nullTokenPos); 286 | } 287 | 288 | return $expectedType; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/InvalidDataTypeException.php: -------------------------------------------------------------------------------- 1 | 8 | * GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690 9 | * https://www.phpexperts.pro/ 10 | * https://github.com/phpexpertsinc/DataTypeValidator 11 | * 12 | * This file is licensed under the MIT License. 13 | */ 14 | 15 | namespace PHPExperts\DataTypeValidator; 16 | 17 | use InvalidArgumentException; 18 | use Throwable; 19 | 20 | class InvalidDataTypeException extends InvalidArgumentException 21 | { 22 | /** 23 | * @param string $message 24 | * @param array $reasons 25 | * @param int $code 26 | * @param Throwable|null $previous 27 | */ 28 | public function __construct(string $message, protected array $reasons = [], int $code = 0, ?Throwable $previous = null) 29 | { 30 | parent::__construct($message, $code, $previous); 31 | } 32 | 33 | /** 34 | * @return array 35 | */ 36 | public function getReasons(): array 37 | { 38 | return $this->reasons; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/IsA.php: -------------------------------------------------------------------------------- 1 | 8 | * GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690 9 | * https://www.phpexperts.pro/ 10 | * https://github.com/phpexpertsinc/DataTypeValidator 11 | * 12 | * This file is licensed under the MIT License. 13 | */ 14 | 15 | namespace PHPExperts\DataTypeValidator; 16 | 17 | interface IsA 18 | { 19 | public const KNOWN_TYPES = ['string', 'int', 'array', 'bool', 'float', 'double', 'object', 'callable', 'resource']; 20 | 21 | public function isStrictValidator(): bool; 22 | public function isMixed(mixed $value): bool; 23 | public function isBool(mixed $value): bool; 24 | public function isInt(mixed $value): bool; 25 | public function isFloat(mixed $value): bool; 26 | public function isString(mixed $value): bool; 27 | public function isArray(mixed $value): bool; 28 | public function isArrayOfSomething(mixed $values, string $dataType): bool; 29 | public function isObject(mixed $value): bool; 30 | public function isCallable(mixed $value): bool; 31 | public function isResource(mixed $value): bool; 32 | public function isFuzzyObject(mixed $value, string $shortName): bool; 33 | public function isSpecificObject(mixed $value, string $fullName): bool; 34 | } 35 | -------------------------------------------------------------------------------- /src/IsADataType.php: -------------------------------------------------------------------------------- 1 | 8 | * GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690 9 | * https://www.phpexperts.pro/ 10 | * https://github.com/phpexpertsinc/DataTypeValidator 11 | * 12 | * This file is licensed under the MIT License. 13 | */ 14 | 15 | namespace PHPExperts\DataTypeValidator; 16 | 17 | use ReflectionClass; 18 | 19 | abstract class IsADataType implements IsA 20 | { 21 | abstract public function isStrictValidator(): bool; 22 | 23 | public function isType(mixed $value, string $dataType): bool 24 | { 25 | $isA = "is{$dataType}"; 26 | 27 | if (!in_array($dataType, IsA::KNOWN_TYPES)) { 28 | $isA = str_contains($dataType, '\\') ? 'isSpecificObject' : 'isFuzzyObject'; 29 | } 30 | 31 | // Thank you, PHP devs, for letting me throw on extra function parameters without even throwing a warning. /no-sarc 32 | return $this->$isA($value, $dataType); 33 | } 34 | 35 | public function isArrayOfSomething(mixed $values, string $dataType): bool 36 | { 37 | if (!$this->isArray($values)) { 38 | return false; 39 | } 40 | 41 | foreach ($values as $value) { 42 | if (!$this->isType($value, $dataType)) { 43 | return false; 44 | } 45 | } 46 | 47 | return true; 48 | } 49 | 50 | public function isObject(mixed $value): bool 51 | { 52 | return is_object($value); 53 | } 54 | 55 | public function isCallable(mixed $value): bool 56 | { 57 | return is_callable($value); 58 | } 59 | 60 | public function isResource(mixed $value): bool 61 | { 62 | return is_resource($value); 63 | } 64 | 65 | public function isFuzzyObject(mixed $value, string $shortName): bool 66 | { 67 | if (!is_object($value)) { 68 | return false; 69 | } 70 | 71 | $actualShortName = (new ReflectionClass($value))->getShortName(); 72 | 73 | return strtolower($shortName) === strtolower($actualShortName); 74 | } 75 | 76 | public function isSpecificObject(mixed $value, string $fullName): bool 77 | { 78 | if (!is_object($value)) { 79 | return false; 80 | } 81 | 82 | return $fullName === $value::class; 83 | } 84 | 85 | public function isMixed($value): bool 86 | { 87 | return true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/IsAFuzzyDataType.php: -------------------------------------------------------------------------------- 1 | 8 | * GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690 9 | * https://www.phpexperts.pro/ 10 | * https://github.com/phpexpertsinc/DataTypeValidator 11 | * 12 | * This file is licensed under the MIT License. 13 | */ 14 | 15 | namespace PHPExperts\DataTypeValidator; 16 | 17 | class IsAFuzzyDataType extends IsADataType implements IsA 18 | { 19 | public function isStrictValidator(): bool 20 | { 21 | return false; 22 | } 23 | 24 | public function isBool(mixed $value): bool 25 | { 26 | $isSpecialType = in_array(gettype($value), ['object', 'resource', 'unknown type']); 27 | if ($isSpecialType === true) { 28 | return false; 29 | } 30 | 31 | $isBool = is_bool($value); 32 | $isNull = $value === null; 33 | $isArray = is_array($value); 34 | $isLooseValue = in_array($value, [true, false, 0, 1, "0", "1"], true); 35 | $isNumericAndGreaterThan0 = is_numeric($value) && $value >= 0.0; 36 | 37 | return $isBool || $isNull || $isArray || $isLooseValue || $isNumericAndGreaterThan0; 38 | } 39 | public function isInt(mixed $value): bool 40 | { 41 | if (!is_numeric($value)) { 42 | return false; 43 | } 44 | 45 | return is_int($value) || filter_var($value, FILTER_VALIDATE_INT) !== false || (float) (int) $value === $value; 46 | } 47 | 48 | public function isFloat(mixed $value): bool 49 | { 50 | return is_float($value) || filter_var($value, FILTER_VALIDATE_FLOAT) !== false; 51 | } 52 | 53 | public function isString(mixed $value): bool 54 | { 55 | return is_string($value); 56 | } 57 | 58 | public function isArray(mixed $value): bool 59 | { 60 | return is_array($value) || $value instanceof \ArrayAccess; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/IsAStrictDataType.php: -------------------------------------------------------------------------------- 1 | 8 | * GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690 9 | * https://www.phpexperts.pro/ 10 | * https://github.com/phpexpertsinc/DataTypeValidator 11 | * 12 | * This file is licensed under the MIT License. 13 | */ 14 | 15 | namespace PHPExperts\DataTypeValidator; 16 | 17 | class IsAStrictDataType extends IsADataType implements IsA 18 | { 19 | public function isStrictValidator(): bool 20 | { 21 | return true; 22 | } 23 | 24 | public function isBool(mixed $value): bool 25 | { 26 | return is_bool($value); 27 | } 28 | 29 | public function isInt(mixed $value): bool 30 | { 31 | return is_int($value); 32 | } 33 | 34 | public function isFloat(mixed $value): bool 35 | { 36 | return is_float($value); 37 | } 38 | 39 | public function isString(mixed $value): bool 40 | { 41 | return is_string($value); 42 | } 43 | 44 | public function isArray(mixed $value): bool 45 | { 46 | return is_array($value); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | php-ci.sh 4 | --------------------------------------------------------------------------------