验证PHP多维数组(可嵌套)以避免无限循环

时间:2017-09-20 07:27:04

标签: php arrays validation recursion multidimensional-array

我正在使用https://github.com/dbushell/Nestable库。

使用库可以正常工作但我想验证请求是一种额外的保护,以避免无限循环,如果有人会手动强制请求(假设)。

我想知道是否有人知道一种优雅的方式来获得这个而不用另一个递归函数来检查父母在某个时候是否会成为一个孩子。

示例:

$data = [
    [
        "id" => 1,
    ],
    [
        *"id"       => 2,*
        "children" => [
            [
                "id" => 3,
            ],
            [
                "id" => 4,
            ],
            [
                "id"       => 5,
                "children" => [
                    [
                        "id" => 6,
                    ],
                    [
                        "id" => 7,
                    ],
                    [
                        "id" => 8,
                        "children" => [
                            [
                                *"id" => 2,*
                            ],
                            [
                                "id" => 10,
                            ],
                        ],
                    ],
                ],
            ],
            [
                "id" => 11,
            ],
            [
                "id" => 12,
            ],
        ],
    ],
    [
        "id" => 13,
    ],
    [
        "id" => 14,
    ],

];

nestableLinks($data);

/**
 * Nestable links.
 *
 * @param      $links
 * @param null $parent_id
 * @param int  $weight
 */
function nestableLinks($links, $parent_id = NULL, $weight = 0)
{
    foreach ($links as $link) {
        $weight++;

        var_dump(['id' => $link['id'], 'parent_id' => $parent_id, 'weight' => $weight]);

        if (array_key_exists('children', $link)) {
            nestableLinks($link['children'], $link['id']);
        }
    }
}

3 个答案:

答案 0 :(得分:1)

您可以使用RecursiveArrayIterator。它必须扩展以满足我们的需求:

class NestedRecursiveArrayIterator extends RecursiveArrayIterator
{
    public function hasChildren()
    {
        return isset($this->current()['children']);
    }

    public function getChildren()
    {
        return new static($this->current()['children']);
    }
}

有了这个课程,我们可以用RecursiveIteratorIterator迭代它:

$iterator = new RecursiveIteratorIterator(
    new NestedRecursiveArrayIterator($data),
    RecursiveIteratorIterator::SELF_FIRST
);

$ancestors = [];
foreach ($iterator as $datum) {
    if ($iterator->getDepth() === 0) {
        $ancestors = [];
    }

    if (isset($ancestors[$datum['id']])) {
        // Invalid child that will cause loop.
        var_dump($datum);
    }

    $ancestors[$datum['id']] = true;
}

这是working demo

答案 1 :(得分:0)

你的逻辑很好看。或者,您可以使用array_walk_recursive  而不是定义自己的迭代逻辑,它将自动迭代变量中的每个数组。

$data = [["id"=>1,],["id"=>2,"children"=>[["id"=>3,],["id"=>4,],["id"=>5,"children"=>[["id"=>2,],["id"=>7,],["id"=>8,],],],["id"=>9,],["id"=>10,],],],["id"=>11,],["id"=>12,],];

function test_print($item, $key) {
    echo "key $key holds: $item\n";
}
array_walk_recursive($data, 'test_print');

答案 2 :(得分:0)

使用在id上编制索引的数组,并在遍历树时插入。如果你在那里找到一个节点,你就有一个循环并返回false。

当所有孩子都归来时,你会回归真实。一个错误的结果,你早点回来。

这可以递归完成,也可以将另一个数组用作节点堆栈。选择取决于你对三者的期望有多深。