22

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?

6 Answers 6

13

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/

Sign up to request clarification or add additional context in comments.

1 Comment

I would have said to XML at first, but JSON is just so much easier to work with... +1
8

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)

Comments

7

It doesn't exist built in.

Maybe try something like (untested):

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

3 Comments

why is it better than array_diff_key?
@YevgeniyAfanasyev to arrray_diff_key "Note This function only checks one dimension of a n-dimensional array. Of course you can check deeper dimensions by using array_diff_key($array1[0], $array2[0]);." php.net/manual/en/…
@mimros array_diff is the same "This function only checks one dimension of a n-dimensional array..." php.net/manual/en/…
3

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

Comments

1

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

Comments

1

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.

4 Comments

To random down-voters: why? Please leave a message. The linked library does indeed meet the needs of the asker, and I have no affiliation to it.
I used that lib and it was good for validating array structures. However, it lacks of error messages support. I can only tell if validation failed, but what exactly went wrong is unknown.
@DmitriyLezhnev Then why not send them some pull requests to fix it?
Package looks abandoned to me. But there is a fork which has some recent commits regarding exception handling. Gonna try it myself: github.com/cdrubin/matchmaker

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.