1

我有一个多维数组,需要验证该数组是否包含正确图层上的必填字段。

有没有很好的方法来实现这一目标?输入可以是数组或 JSON。

到目前为止我的方法:

假设输入数组如下:

 Array (
    [key] => key string
    [sub] => Array (
        [0] => Array (
            [id] => 123456
            [src] => source string
            [src_ids] => Array (
                [0] => 1
                [1] => 2
                [2] => 3
                [3] => 4
            )
            [data] => Array (
                [a_data] => a string
                [b_data] => b string
                [c_data] => c string
            )
        )
        [1] => Array (
            [id] => 557799
            [src] => source string
            [src_ids] => Array (
                [0] => 1
                [1] => 2
            )
            [data] => Array (
                [a_data] => a string
                [b_data] => b string
                [c_data] => c string
            )
        )
    )
)

强制值是:

sub, id, src, src_ids, data, a_data

可选值是其他所有内容,例如:

key, 0 (of sub), 0-3 (of src_ids), b_data, c_data

我想要一个函数来检查任何输入数组与必填字段。我的想法是将强制值创建为基于层的数组,例如:

$mandatory = array( 
    1 => array( 'sub' ),
    3 => array( 'id', 'src', 'src_id', 'data' ),
    4 => array( 'a_data' )
);

键是层的深度,数组值是该层允许的键名。

现在我尝试爬取输入数组并根据深度检查键是否在必填字段中:

/**
 * 
 * @param array $i input
 * @param array $m mandatory
 * @param integer $d depth
 * @return boolean
 */
function validate( $i, $m, $d=1 ) {
    foreach( $i as $k => $v ) {
        if( isset($m[$d]) ) {
            if( !in_array($k, $m[$d]) ) {
                return false;
            } else {
                if( is_array($v) ) {
                    $d++;
                    validate($v, $m, $d );
                }
            }
        } else {
            if( is_array($v) ) {
                $d++;
                validate($v, $m, $d );
            }
        }
    }
    return true;
}

但这会导致两个主要问题:

  1. 第 4 层包含 src_ids 和数据的数组,但只有在数据中才有必填字段 a_data。所以它将为第 4 层返回 false
  2. 但主要问题是这个函数的逻辑问题。现在它不检查是否设置了必填字段,它只检查深度的输入值是否在必填字段中。这种行为是错误的。

我也尝试使用比较数组,但由于有多个条目,我无法将所有条目与强制数组进行比较。

非常感谢任何帮助、建议或解决方案。

谢谢

4

2 回答 2

1

这是否满足您的要求?

必填字段结构:

$required = array(
    'sub' => array(
        array(
            'id' => '',
            'src' => '',
            'src_ids' => '',
            'data' => array(
                'a_data' => '',
            ),
        ),
    ),
);

基本上只是模仿输入数组的结构。字段名是键;必需的子字段是后代。sub[0]如果它是一个与and一样的列表,则保留数字键/未命名键sub[1],它将检查列表中每个项目的结构。

递归验证函数:

function checkRequired($data, $req)
{
    // no more required fields
    if (empty($req))
        return true;

    // no more data fields; obviously lacks required field(s)
    if (empty($data))
        return false;

    foreach ($req as $name => $subtree) {
        // unnamed; it's a list
        if (is_numeric($name)) {
            foreach ($data as $dataitem) {
                if (checkRequired($dataitem, $subtree) == false)
                    return false;
            }
        } else {
            // required field doesn't exist
            if (!isset($data[$name]))
                return false;

            // fine so far; down we go
            if (!empty($subtree)
                && checkRequired($data[$name], $subtree) == false
            ) {
                return false;
            }
        }
    }

    return true;
}

我可能在某个地方搞砸了,但希望你能把它改编成有用的东西。这是一个您可以尝试的工作示例。

于 2012-07-12T19:31:09.500 回答
1

如果你定义$input$mandatory描述的那样,剩下的代码看起来像这样:

$values[1] = $input;
$layer = 1;
$found_layer = true;

while($found_layer)
{
        $found_layer = false;
        foreach($values[$layer] as $li=>$le)
        {
                if(is_array($le))
                {
                        $found_layer = true;
                        if(!isset($values[$layer+1])) $values[$layer+1] = array();
                        $values[$layer+1] = array_merge($le, $values[$layer+1]);
                        $values[$layer][$li] = 'array';
                }
        }
        $layer++;
}

$not_found = $mandatory;

foreach($not_found as $layer=>$keys_to_match)
{
        foreach($values[$layer] as $key=>$value)
        {
                foreach($keys_to_match as $ktmi=>$ktm)
                {
                        if($ktm==$key) unset($not_found[$layer][$ktmi]);
                }
        }
        if(!count($not_found[$layer])) unset($not_found[$layer]);
        else $not_found[$layer] = array_values($not_found[$layer]);
}

那么代码将产生$not_found如下:

Array
(
    [3] => Array
        (
            [0] => src_id
        )

)

这意味着,根据$mandatory. 如果找到所有必需元素,$not_found则将为空。注意,你有'src_id'in$mandatory$input显然只有一个 key 'src_ids'

我避免使用递归来提高性能。

于 2012-07-12T19:54:31.620 回答