【问题标题】:PHP - Checking an array for required keys and setting optional key-valuesPHP - 检查所需键的数组并设置可选键值
【发布时间】:2015-02-06 14:39:23
【问题描述】:

我正在构建一个接收一组数据的 Web API。我想检查这个数组中的某些键,如果需要的键不存在,则返回 false,如果可选的键不存在,则在数组中设置该键值对。

混淆来自于我的输入数组具有潜在的数组作为值。例如,假设我输入了一个这样的数组:

$input_array = array(
    ’name’ => ‘Adam’,
    ‘address’ => array(
        ‘number’ => 12,
        ‘street’ => ‘My Street’
    )
);

我有所需的密钥:

$required_keys = array(
    ‘name’,
    ‘address’ => array(
        ‘number’,
        ‘street’
    )
);

可选键:

$optional_keys = array(
    ‘address’ = array(
        ‘postcode’ => ‘WA1'
    )
);

我正在努力寻找一种方法来针对这两种类型的测试数组(输入和可选)测试我的输入数组。

应该发生的是: 1) 应匹配所有必需的键。 2)如果任何可选键不存在,则将它们设置为可选键数组中的键值对。

我知道(但不熟悉)正则表达式。但是,我知道 PHP 有一个名为 http_build_query(mixed $array); 的函数,它接受一个数组并将其转换为 URL 查询字符串。我的想法是也许我可以将输入数组转换为 URL 字符串,然后将其与由我的两个测试数组(必需和可选)组成的正则表达式进行比较。这会/可以吗?

如果有人有任何其他想法,我很想知道。 谢谢

更新:附加意外输出

更新 2:附加新输出

更新 3:当前代码:

static public function static_test_required_keys(Array $required_keys_array, Array $input_array)
{
    $missing = array();

    foreach ($required_keys_array as $key => $value)
    {
        if (empty($input_array[$key]))
        {
            $missing[] = $key;
        }
        else if (isset($input_array[$key]) && is_array($input_array[$key]))
        {
            $missing = array_merge(Inputter::static_test_required_keys($value, $input_array[$key]), $missing);
        }
    }

    return $missing;
}

更新 4:新代码。

tatic public function static_test_required_keys(Array $required_keys_array, Array $input_array)
{
    $missing = array();

    foreach ($required_keys_array as $key => $value)
    {
        if (! isset($input_array[$key]))
        {
            $missing[] = $key;
        }
        else if (isset($input_array[$key]) && is_array($input_array[$key]))
        {
            $missing = array_merge(Inputter::static_test_required_keys($value, $input_array[$key]), $missing);
        }
    }

    return $missing;
}

将代码从isempty() 更改为isset()。这个页面给出了两者之间的区别。 https://www.virendrachandak.com/techtalk/php-isset-vs-empty-vs-is_null/

【问题讨论】:

标签: php arrays regex


【解决方案1】:

必填字段

您可以使用array_diff 检查输入中是否缺少任何必填字段。

可选字段

您可以使用array_merge 设置缺失字段的默认值。

代码

$requiredKeys = [
   'foo',
   'baz',
];

// Take the keys from input
$inputKeys = array_keys($input);

$missingRequiredKeys = array_diff($requiredKeys, $inputKeys)
if (!empty($missingRequiredKeys)) {
    throw new InvalidArgumentException(...);
}

// Setup default values for missing optional keys
$defaultValues = [
   'bar' => 'bas',
];

$result = array_merge($defaultValues, $input);

子数组

要检查必填字段或设置默认值,只需在各个函数中重复上述代码。

function validateInput(array $input) {
   // Above code

   // Validate field subkeys from a parent required field.
   // or optional field with default value.
   validateFoo($input['foo']);

   // Validate field subkeys from a parent optional field without default value.
   if (array_key_exists('optional_input_without_default', $input)) {
       validateAnotherFooInput($input['optional_input_without_default']);
   }
}

其他选项

您可以通过多种方式使用数组交集、差异和合并来检查Array Book 中的那些函数族

array_diff_assoc — 通过附加索引检查计算数组的差异

array_diff_key — 使用键计算数组的差异以进行比较

array_diff_uassoc — 通过用户提供的回调函数执行的附加索引检查计算数组的差异

array_diff_ukey — 使用键上的回调函数计算数组的差异以进行比较

array_diff — 计算数组的差异

array_intersect_assoc — 通过附加索引检查计算数组的交集

array_intersect_key — 使用键计算数组的交集以进行比较

array_intersect_uassoc — 通过附加索引检查计算数组的交集,通过回调函数比较索引

array_intersect_ukey — 使用键上的回调函数计算数组的交集以进行比较

array_intersect — 计算数组的交集

array_udiff_assoc — 通过附加索引检查计算数组的差异,通过回调函数比较数据

array_udiff_uassoc — 通过附加索引检查计算数组的差异,通过回调函数比较数据和索引

array_udiff — 通过使用回调函数计算数组的差异进行数据比较

array_uintersect_assoc — 通过附加索引检查计算数组的交集,通过回调函数比较数据

array_uintersect_uassoc — 通过附加索引检查计算数组的交集,通过回调函数比较数据和索引

array_uintersect — 计算数组的交集,通过回调函数比较数据

【讨论】:

  • 值得注意的是:短数组语法仅适用于 php >= 5.4,您的答案 $input$inpuKeys 中还有一些未定义的变量,并且您的 if 语句出现致命错误.. 没有关闭)
  • array_diff!好主意。
【解决方案2】:

对称输入+必填键的新改进版本...

$input_array = array(
    'name' => 'Adam',
    'address' => array(
        'number' => 12,
        'street' => '',
        'phones' => array('home_phone'=>'','fax'=>'555-1212')
    )
);

$required_keys = array(
    'name' => '',
    'address' => array(
        'number' => '',
        'street' => '',
        'phones' => array('home_phone'=>'')
    )
);


function check_required( $input, $required ){
    $missing = array();
    foreach ($required as $k=>$v) {
        if (empty($input[$k])) {
            $missing[] = $k;
        } else if (is_array($v)) {
            $missing = array_merge( check_required( $input[$k], $v ), $missing );
        }
    }
    return $missing;
}

$missing = check_required( $input_array, $required_keys );
if (!empty($missing)) echo 'Please enter your '. implode(', ', $missing);

在这里查看沙盒...http://sandbox.onlinephpfunctions.com/code/23b908b873b053aefb37770f636b63bba2db960b

【讨论】:

  • 我的输入数组必须是多维的。输入数组来自 JSON POST,可以是多维的。
  • 更新了无限深度多维数组检查的答案
  • 感谢您的帮助。这确实有效,但我刚刚意识到我的数据(被 JSON 编码)可能包含索引数组。例如,‘addresses’ => array( ‘address’ => array(‘number’ => 13, ’street’ => ‘My Street’), ‘address’ => array(‘number’ => 14, ‘street’ => ‘My Street’))
  • 只要 $input_array 的结构被 $required_keys 镜像(有点,因为键和值被交换了),它就可以工作
  • 是的,你是对的。在测试期间,我的“寻址”应该在我的 required_keys 中的索引数组中。非常感谢你的帮助。在 optional_keys 方面,一个简单的 array_merge 会起作用吗(正如@Maks3w 建议的那样)?
【解决方案3】:
// Check if required keys exist
foreach( $required_keys as $req_key => $req_val )
{
    if( !array_key_exists( $req_key, $input_array )
    {
        // if key exists check if it has values set in an array and if 
        // these are also in $input_array
        if( is_array( $req_val ) )
        {
            foreach( $req_val as $inner_req_key )
            {
                if( !isset( $input_array[$req_val][$inner_req_key] )
                {
                    echo "Required key '$req_key' is missing value '$inner_req_key'.";
                }
            }
        }
        echo "Required key '$req_key' is missing.";
    }
}

// Check if optional keys are defined
foreach( $optional_keys as $opt_key => $opt_val )
{
    // Check if key exists, if not copy optional key=>value as whole
    if( !array_key_exists( $opt_key, $input_array )
    {
        $input_array[ $opt_key ] = $opt_val;
    }
    else // key exists
    {
        // if key exists check if it is an array and if optional elements
        // exist, else add them
        if( is_array( $opt_key ) )
        {
            foreach( $opt_key as $inner_opt_key => $inner_opt_val )
            {
                // key is not set, so get from %optional_keys
                if( !isset( $input_array[$opt_key][$inner_opt_key] )
                {
                    $input_array[$opt_key][$inner_opt_key] = $inner_opt_val;
                }
            }
        }
    }
}

很久没有 PHP,但也许这会有所帮助。 PS:未经测试并添加了一些解释。高温

【讨论】:

    【解决方案4】:

    所以这是我的最终代码,供任何偶然发现此/想知道我是如何做到的人的。随时提交改进意见。

    static protected function static_test_required_keys(Array $required_keys_array, Array $input_array, &$error)
    {
        //  Loop through each required key and value
        //
        foreach ($required_keys_array as $key => $value)
        {
            //  Check the corresponding value in the input array is not set
            //
            if (! isset($input_array[$key]))
            {
                //  If it isn't set return false with a missing error
                //
                $error = Error::withDomain(INPUTTER_ERROR_DOMAIN,
                                           INPUTTER_ERROR_CODE_KEY_MISSING,
                                           'Missing a required key: ' . $key);
    
                return false;
            }
            //
            //  Check corresponding value in the input array is set and is an array
            //
            else if (isset($input_array[$key]) && is_array($input_array[$key]))
            {
                //  Recurse the function for sub arrays
                //
                if (! Inputter::static_test_required_keys($value, $input_array[$key], $error))
                {
                    //  If we return false from this one, we've found at least one error and don't need to continue
                    //
                    return false;
                }
            }
        }
    
        //  If we get here then it must be valid
        //
        return true;
    }
    
    static protected function static_set_optional_key_values(Array $optional_dictionary, Array &$input_array, &$error)
    {
        //  Loop through each optional key/value
        //
        foreach ($optional_dictionary as $key => $value)
        {
            //  Check the key doesn't exist in the input array OR the corresponding value in the input array is not set
            //
            if (! array_key_exists($key, $input_array) || ! isset($input_array[$key]))
            {
                //  Set the new key/value
                //              
                $input_array[$key] = $value;
            }
            //
            //  Check corresponding value in the input array is set and is an array
            //
            else if (isset($input_array[$key]) && is_array($input_array[$key]))
            {
                //  Recurse the function for sub arrays
                //
                Inputter::static_set_optional_key_values($value, $input_array[$key], $error);
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      我不知道你想在哪里运行这段代码。

      如果它在浏览器中或在 Javascript 中。

      因为我有疑问,所以我做了这个:

      function array_extend() {
      
          //Detects if we are running in Javascript or PHP
          //In PHP, this will be false because PHP only parses
          //escape sequences in double-quoted strings (except the sequence \')
          $javascript = '\0' == "\0";
      
          //PHP arrays support 'key=>value' pairs, JS arrays don't.
          $result = $javascript ? new Object() : array();
      
          $arguments = $javascript? arguments : func_get_args();
      
          $get_keys = function($elem){
              if('\0' == "\0")//PHP complains if I use the var $javascript
              {
                  $object = Object;
                  return $object['keys']($elem); //PHP doesn't like the Object.keys syntax
              }
              else
              {
                  return array_keys($elem);
              }
          };
      
      
          for($j = 0, $length_args = $javascript? $arguments['length']: count($arguments); $j < $length_args; $j++)
          {
              $keys = $get_keys( $arguments[$j] );
      
              for($i = 0, $length_keys = $javascript? $keys['length']: count($keys); $i < $length_keys; $i++)
              {
                  $result[$keys[$i]] = $arguments[$j][$keys[$i]];
              }
          }
      
          return $result;
      }
      

      它可以在 PHP 和 Javascript 中运行。

      目前,我在另一个网站上有一个未解决的问题,展示了该功能。

      您可以继续https://codereview.stackexchange.com/questions/79804/polyglot-array-extend-function-for-javascript-and-php查看。

      【讨论】:

        猜你喜欢
        • 2011-07-24
        • 2019-02-07
        • 1970-01-01
        • 1970-01-01
        • 2012-06-15
        • 2015-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多