将多维数组与强制值进行比较

时间:2012-07-12 18:20:35

标签: php arrays json

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

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

到目前为止我的approche:

让我们假设输入数组如下:

 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层
  2. ,它将返回false
  3. 但主要问题是此功能的逻辑问题。现在它不会检查必填字段是否设置,它只检查深度的输入值是否在必填字段中。这种行为是错误的。
  4. 我也尝试使用比较数组,但由于多个条目,我无法将所有条目与强制数组进行比较。

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

    由于

2 个答案:

答案 0 :(得分:1)

这是否符合您的要求?

必填字段结构:

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

基本上只是模仿输入数组的结构。字段名称是键;必需的子字段是后代。如果它是与sub[0]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;
}

我可能会在某个地方蠢蠢欲动,但希望你可以将它改编成有用的东西。这是你可以试验的working example of this

答案 1 :(得分: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
        )

)

这意味着,在输入的第三级(“层”)上没有使用键“src_id”的元素,根据$mandatory这是必需的。如果找到所有必需元素,则$not_found将为空。请注意,'src_id'中有$mandatory,但$input显然只有一个键'src_ids'

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