<?php
$userJson = '{
"name":"Vasya",
"surname":"Popov",
"age":33,
"address":{
"street":"Pushkina",
"house":"Kolotushkina"
}
}';
$badUserJson = '{
"name":"Vasya",
"surname":"Popov",
"age":"33",
"address":{
"street":"Pushkina",
"house":"Kolotushkina"
}
}';
$noAgeUserJson = '{
"name":"Vasya",
"surname":"Popov",
"address":{
"street":"Pushkina",
"house":"Kolotushkina"
}
}';
$noAddressUserJson = '{
"name":"Vasya",
"surname":"Popov"
}';
/**
* @property-read string $name
* @property-read string $surname
* @property-read AddressData $address
*/
class UserData {}
/**
* @property-read string $street
* @property-read string $house
*/
class AddressData {}
class JsonValidator
{
protected const IS_STRING = 'static::isString';
protected const IS_INT = 'static::isInt';
protected static $assertions = [];
protected static function isString($value) : void
{
if (false === is_string($value)) {
throw new Exception(
'Wrong json value type. Expected: "string" received: "' . gettype($value) . '" value: "' . $value . '"'
);
}
}
protected static function isInt($value) : void
{
if (false === is_int($value)) {
throw new Exception(
'Wrong json value type. Expected: "int" received: "' . gettype($value) . '" value: "' . $value . '"'
);
}
}
public static function validate(object $data): array
{
$allErrors = [];
set_error_handler(static function($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
foreach (static::$assertions as $parameterName => $assertionFunction) {
try {
$parameterValue = $data->$parameterName;
$errors = call_user_func($assertionFunction, $parameterValue);
} catch (Throwable $exception) {
$allErrors[$parameterName][] = $exception->getMessage();
}
if (isset($errors) && count($errors)) {
$allErrors[$parameterName] = $errors;
}
}
restore_error_handler();
return $allErrors;
}
}
class UserDataValidator extends JsonValidator
{
private const IS_ADDRESS = 'AddressDataValidator::validate';
protected static $assertions = [
'name' => self::IS_STRING,
'surname' => self::IS_STRING,
'age' => self::IS_INT,
'address' => self::IS_ADDRESS,
];
}
class AddressDataValidator extends JsonValidator
{
protected static $assertions = [
'street' => self::IS_STRING,
'house' => self::IS_STRING,
];
}
/** @var UserData $userData */
$userData = json_decode($userJson, false);
var_dump($userData);
$errors = UserDataValidator::validate($userData);
print_r($errors);
/** @var UserData $userData */
$userData = json_decode($badUserJson, false);
var_dump($userData);
$errors = UserDataValidator::validate($userData);
print_r($errors);
/** @var UserData $userData */
$userData = json_decode($noAgeUserJson, false);
var_dump($userData);
$errors = UserDataValidator::validate($userData);
print_r($errors);
/** @var UserData $userData */
$userData = json_decode($noAddressUserJson, false);
var_dump($userData);
$errors = UserDataValidator::validate($userData);
print_r($errors);
- Output for 8.2.0 - 8.2.19, 8.3.0 - 8.3.7
- object(stdClass)#1 (4) {
["name"]=>
string(5) "Vasya"
["surname"]=>
string(5) "Popov"
["age"]=>
int(33)
["address"]=>
object(stdClass)#2 (2) {
["street"]=>
string(8) "Pushkina"
["house"]=>
string(12) "Kolotushkina"
}
}
Process exited with code 137. - Output for 7.4.33, 8.0.1 - 8.0.30, 8.1.0 - 8.1.28
- object(stdClass)#1 (4) {
["name"]=>
string(5) "Vasya"
["surname"]=>
string(5) "Popov"
["age"]=>
int(33)
["address"]=>
object(stdClass)#2 (2) {
["street"]=>
string(8) "Pushkina"
["house"]=>
string(12) "Kolotushkina"
}
}
Array
(
)
object(stdClass)#3 (4) {
["name"]=>
string(5) "Vasya"
["surname"]=>
string(5) "Popov"
["age"]=>
string(2) "33"
["address"]=>
object(stdClass)#4 (2) {
["street"]=>
string(8) "Pushkina"
["house"]=>
string(12) "Kolotushkina"
}
}
Array
(
[age] => Array
(
[0] => Wrong json value type. Expected: "int" received: "string" value: "33"
)
)
object(stdClass)#2 (3) {
["name"]=>
string(5) "Vasya"
["surname"]=>
string(5) "Popov"
["address"]=>
object(stdClass)#1 (2) {
["street"]=>
string(8) "Pushkina"
["house"]=>
string(12) "Kolotushkina"
}
}
Array
(
[age] => Array
(
[0] => Undefined property: stdClass::$age
)
)
object(stdClass)#4 (2) {
["name"]=>
string(5) "Vasya"
["surname"]=>
string(5) "Popov"
}
Array
(
[age] => Array
(
[0] => Undefined property: stdClass::$age
)
[address] => Array
(
[0] => Undefined property: stdClass::$address
)
)
preferences:
108.97 ms | 405 KiB | 92 Q