数组包含某个结构

时间:2017-03-25 15:19:07

标签: php arrays multidimensional-array

当使用数组做复杂的事情时,我很快就会感到困惑。

我正在尝试创建一个函数arrayStructure($candidate, $structure)

  • 检查candidate数组是否包含给定的structure

我有什么:

// The array that will be validated
$candidate = [
    'persons' => [
        'john',
        'amanda'
    ],
    'animals' => [
        'dog',
        'monkey'
    ],
    'aliens' => 'scary_one'
];

// The structure the candidate has to contain
$structure = ['persons', 'animals' => ['species'] ];

arrayStructure($candidate, $structure);

这应返回 false ,因为$candidate['animals']没有密钥species

现在,如果我们要向$candidate['animals']添加一个物种数组,就像这样:

$candidate = [
    'persons' => [
        'john',
        'amanda'
    ],
    'animals' => [
        'species' => [],
        'dog',
        'monkey'
    ],
    'aliens' => 'scary_one'
];

// The structure the candidate has to contain
$structure = ['persons', 'animals' => ['species'] ];

arrayStructure($candidate, $structure);

这将返回 true ,因为$ candidate 包含 $structure中给出的结构。

请注意以下事项:

  • 应该递归检查结构和候选人
  • 结构包含键和值:persons不是键,而是,但它会查找persons 候选人。 species也是如此。
  • 候选人和结构都是多维的。
  • 函数arrayStructure检查候选者是否包含键,这就是为什么它会在第二个例子中返回true,即使候选者包含“外星人”而结构不包含“外星人”。

有没有人知道如何才能做到这一点?

Laravel在PHPUnit帮助函数assertJsonStructure中执行与JSON结构类似的操作:

public function assertJsonStructure(array $structure = null, $responseData = null)
{
    if (is_null($structure)) {
        return $this->assertJson();
    }

    if (is_null($responseData)) {
        $responseData = $this->decodeResponseJson();
    }

    foreach ($structure as $key => $value) {
        if (is_array($value) && $key === '*') {
            PHPUnit::assertInternalType('array', $responseData);

            foreach ($responseData as $responseDataItem) {
                $this->assertJsonStructure($structure['*'], $responseDataItem);
            }
        } elseif (is_array($value)) {
            PHPUnit::assertArrayHasKey($key, $responseData);

            $this->assertJsonStructure($structure[$key], $responseData[$key]);
        } else {
            PHPUnit::assertArrayHasKey($value, $responseData);
        }
    }

    return $this;
}

使数组变得更简单(当我使用上面的示例运行PHPUNIT测试时,这项工作):

public function assertArrayStructure(array $structure = null, array $array)
{
    foreach ($structure as $key => $value) {
        if (is_array($value)) {
            PHPUnit::assertArrayHasKey($key, $array);

            $this->assertArrayStructure($structure[$key], $array[$key]);
        } else {
            PHPUnit::assertArrayHasKey($value, $array);
        }
    }

    return $this;
}

这也是我在自己的实验中所拥有的,除了我无法让数组有工作的关键(PHPUnit做了一些额外的事情,我想弄清楚)。

1 个答案:

答案 0 :(得分:0)

function arrayStructure(array $structure = null, array $array, &$errors = [])
{
    foreach ($structure as $key => $value) {
        if (is_array($value)) {
            if (!array_key_exists($key, $array)) $errors[] = false;
            arrayStructure($structure[$key], $array[$key], $errors);
        } else {
            if (!array_key_exists($value, $array)) $errors[] = false;
        }
    }

    return empty($errors);
}

如果密钥不存在,我们会不断添加$errors数组,这意味着如果错误不为空,则候选人没有结构。这个成功了:

persons is checked in: {"persons":["john","amanda"],"animals":{"species":[],"0":"dog","1":"monkey"},"other":"value"}
animals is checked in: {"persons":["john","amanda"],"animals":{"species":[],"0":"dog","1":"monkey"},"other":"value"}
species is checked in: {"species":[],"0":"dog","1":"monkey"}
bool(true)

现在,如果我们移除物种,它将失败:

persons is checked in: {"persons":["john","amanda"],"animals":["dog","monkey"],"other":"value"}
animals is checked in: {"persons":["john","amanda"],"animals":["dog","monkey"],"other":"value"}
species is checked in: ["dog","monkey"]
bool(false)