Reputation: 9295
is it possible to dynamically check if two objects schema is the same (in php)? for example:
{
name: "Name1",
age: 2,
kids: [1,3,4]
}
{
name: "Name2",
age: 2,
kids: [1,6,4,3]
}
For the above example I am expecting to return true. Here is another example:
{
name: "Name1",
age: 2,
kids: [1,3,4]
}
{
name: "Name1",
kids: [1,3,4]
}
Here I am expecting to get false (schema not the same: age missing from the second object).
The function definition should look like: Boolean isSchemaEqual($obj1, $obj2)
(I know there are no function definitions in php, just did it in order to make my question more clear).
Note: the schema could be nested, in that I mean some property can hold an object which also needs to be checked against the other object's (same) property.
Upvotes: 1
Views: 421
Reputation: 21130
If you're looking to validate multiple levels of schema, you can use recursion in conjunction with an order-less array comparison idiom for the keys.
// determines if an array is associative
function isAssociative($array) {
return (bool)count(array_filter(array_keys($array), 'is_string'));
}
// determines if the keys of two arrays are equal regardless of order
function keysEqual($a, $b) {
if (!is_array($a) || !is_array($b))
return false;
$keysA = array_keys($a);
$keysB = array_keys($b);
return array_diff($keysA, $keysB) === array_diff($keysB, $keysA);
}
function isSchemaEqual($a, $b) {
// validate keys - basic validation
if (!keysEqual($a, $b))
return false;
// if we come across any key where the value is associative and
// the schema isn't the same for b's value at $key, then we know
// the schemas aren't equal
foreach ($a as $key => $value) {
if (is_array($value) && isAssociative($value) && !isSchemaEqual($value, $b[$key]))
return false;
}
// we couldn't find any differences, so they're equal
return true;
}
You can find some tests, here.
Upvotes: 2
Reputation: 26729
Compare the keys:
if (array_keys($schema1) == array_keys($schema2)) {
}
For nested object, you will have to make your own function. One approach would be to make it one-level, with paths like {kids: {boys: [1,2,3]}}
becoming kids/boys
, then you can compare the arrays:
function flatten_keys($object, $prefix = '') {
$result = array();
foreach ($object as $key=>$value) {
$result[] = $prefix . $key;
if (is_object($value) || (is_array($value) && array_values($value) != $value) ) {
$result = array_merge($result, flatten_keys($value, $key .'/'));
}
}
return $result;
}
$a = flatten_keys($schema2);
$b = flatten_keys($schema2);
sort($a);
sort($b);
if ($a == $b){
}
Upvotes: 0