user151841
user151841

Reputation: 18046

How can I validate the structure of my PHP arrays?

Is there a function out there to make sure that any given array conforms to a particular structure? What I mean is that is has particular key names, perhaps particular types for values, and whatever nested structure.

Right now I have a place where I want to make sure that the array getting past has certain keys, a couple holding a certain data type, and one sub-array with particular key names. I've done a lot of run-around because I was passing malformed arrays to it, and finally I'm at the point where I have a bunch of

if ( ! isset($arr['key1']) ) { .... }
if ( ! isset($arr['key2']) ) { .... }
if ( ! isset($arr['key3']) ) { .... }

I would have saved a lot of time and consternation if I could have checked that the array conformed to a particular structure beforehand. Ideally something like

$arrModel = array(
    'key1' => NULL ,
    'key2' => int ,
    'key3' => array(
        'key1' => NULL ,
        'key2' => NULL ,
      ),
);

if ( ! validate_array( $arrModel, $arrCandidate ) ) { ... }

So, the question I'm asking is, does this already exists, or do I write this myself?

Upvotes: 22

Views: 15488

Answers (6)

Jefferson Lima
Jefferson Lima

Reputation: 5436

You can use the Symfony Validation component

Installation:

 composer require symfony/validator doctrine/annotations

Usage:

$myArray = [
  'name' => ['first_name' => 'foo', 'last_name' => 'bar'],
  'email' => '[email protected]' 
];

$constraints = new Assert\Collection([
    'name' => new Assert\Collection([
        'first_name' => new Assert\Length(['min' => 101]),
        'last_name' => new Assert\Length(['min' => 1]),
    ]),
    'email' => new Assert\Email(),
]);

$validator = Validation::createValidator();
$violations = $validator->validate($myArray, $constraints);

For more details, see How to Validate Raw Values (Scalar Values and Arrays)

Upvotes: 8

ETNyx
ETNyx

Reputation: 190

accepted answer make diff based on values, since it's about array structure you dont want to diff values. Insted you should use [array_diff_key()][1]

Function alone is not recursive. It will not work out of box on sample array from question.


Edit after years: Got into similar trouble whit recursive array functions, so there is mine array_diff_recursive, this does not solve original question because it compare values as well, but i believe it can be easily modified and someone can find it useful .

function array_diff_recursive(array $array1, array $array2){
    return array_replace_recursive(
        array_diff_recursive_one_way($array1, $array2),
        array_diff_recursive_one_way($array2, $array1)
    );
}//end array_diff_recursive()

function array_diff_recursive_one_way(array $array1, array $array2)
{
    $ret = array();

    foreach ($array1 as $key => $value) {
        if (array_key_exists($key, $array2) === TRUE) {
            if (is_array($value) === TRUE) {
                $recurse = array_diff_recursive_one_way($value, $array2[$key]);
                if (count($recurse) > 0) {
                    $ret[$key] = $recurse;
                }
            } elseif (in_array($value, $array2) === FALSE) {
                $ret[$key] = $value;
            }
        } elseif (in_array($value, $array2) === FALSE) {
            $ret[$key] = $value;
        }
    }

    return $ret;
}//end array_diff_recursive_one_way()```

[1]: http://php.net/manual/en/function.array-diff-key.php

Upvotes: 3

Nicholas Shanks
Nicholas Shanks

Reputation: 10981

I came across a tool called Matchmaker on GitHub, which looks very comprehensive and has composer support and unit tests:
https://github.com/ptrofimov/matchmaker

You can include it into your project with composer require ptrofimov/matchmaker.

Upvotes: 1

Enric
Enric

Reputation: 11

I know this is sort of an old post, sorry if my answer is not approppriate.

I'm in the process of writing a php package that does exactly what you are asking for, it's called Structure.

What you can do with the package is something like:

$arrayCheck = new \Structure\ArrayS();
$arrayCheck->setFormat(array("profile"=>"array"));
if ($arrayCheck->check($myArray)) {
    //...
}

You can check it out here: http://github.com/3nr1c/structure

Upvotes: 1

Parris Varney
Parris Varney

Reputation: 11478

It doesn't exist built in.

Maybe try something like (untested):

array_diff(array_merge_recursive($arrCandidate, $arrModel), $arrModel)

Upvotes: 7

webbiedave
webbiedave

Reputation: 48887

Convert array to JSON:

http://us.php.net/manual/en/function.json-encode.php

Then check against a JSON Schema:

http://json-schema.org/

http://jsonschemaphpv.sourceforge.net/

Upvotes: 13

Related Questions