php 为 foreach() 提供的参数无效

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2630013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 07:09:36  来源:igfitidea点击:

Invalid argument supplied for foreach()

phpforeach

提问by Roberto Aloi

It often happens to me to handle data that can be either an array or a null variable and to feed some foreachwith these data.

我经常遇到处理可以是数组或空变量的数据并foreach用这些数据提供一些数据的情况。

$values = get_values();

foreach ($values as $value){
  ...
}

When you feed a foreach with data that are not an array, you get a warning:

当您使用非数组数据为 foreach 提供数据时,您会收到警告:

Warning: Invalid argument supplied for foreach() in [...]

警告:为 [...] 中的 foreach() 提供的参数无效

Assuming it's not possible to refactor the get_values()function to always return an array (backward compatibility, not available source code, whatever other reason), I'm wondering which is the cleanest and most efficient way to avoid these warnings:

假设不可能重构get_values()函数以始终返回数组(向后兼容性,不可用的源代码,无论其他原因),我想知道哪种方法是避免这些警告的最干净和最有效的方法:

  • Casting $valuesto array
  • Initializing $valuesto array
  • Wrapping the foreachwith an if
  • Other (please suggest)
  • 投射$values到数组
  • 初始化$values为数组
  • foreach用一个包裹if
  • 其他(请推荐)

回答by Andy Shellam

Personally I find this to be the most clean - not sure if it's the most efficient, mind!

我个人认为这是最干净的 - 不确定它是否最有效,注意!

if (is_array($values) || is_object($values))
{
    foreach ($values as $value)
    {
        ...
    }
}

The reason for my preference is it doesn't allocate an empty array when you've got nothing to begin with anyway.

我偏爱的原因是,当你一无所有时,它不会分配空数组。

回答by Ajith R Nair

How about this one? lot cleaner and all in single line.

这个怎么样?更清洁,全部在单行中。

foreach ((array) $items as $item) {
 // ...
 }

回答by Kris

I usually use a construct similar to this:

我通常使用与此类似的构造:

/**
 * Determine if a variable is iterable. i.e. can be used to loop over.
 *
 * @return bool
 */
function is_iterable($var)
{
    return $var !== null 
        && (is_array($var) 
            || $var instanceof Traversable 
            || $var instanceof Iterator 
            || $var instanceof IteratorAggregate
            );
}

$values = get_values();

if (is_iterable($values))
{
    foreach ($values as $value)
    {
        // do stuff...
    }
}

Note that this particular version is not tested, its typed directly into SO from memory.

请注意,这个特定版本没有经过测试,它直接从内存中输入到 SO 中。

Edit:added Traversablecheck

编辑:添加了可遍历检查

回答by AARTT

Please do not depend on casting as a solution, even though others are suggesting this as a valid option to prevent an error, it might cause another one.

请不要依赖强制转换作为解决方案,即使其他人建议这是防止错误的有效选项,但它可能会导致另一个错误。

Be aware:If you expect a specific form of array to be returned, this might fail you. More checks are required for that.

请注意:如果您希望返回特定形式的数组,这可能会让您失望。为此需要进行更多检查。

E.g. casting a boolean to an array (array)bool, will NOTresult in an empty array, but an array with one element containing the boolean value as an int: [0=>0]or [0=>1].

例如(array)bool,将boolean 转换为 array ,不会导致空数组,而是一个包含布尔值作为 int: [0=>0]or 的元素的数组[0=>1]

I wrote a quick test to present this problem. (Here is a backup Testin case the first test url fails.)

我写了一个快速测试来呈现这个问题。(这是一个备份测试,以防第一个测试 url 失败。)

Included are tests for: null, false, true, a class, an arrayand undefined.

包括以下测试:null, false, true, a class, anarrayundefined



Always test your input before using it in foreach. Suggestions:

在 foreach 中使用之前,请务必测试您的输入。建议:

  1. Quick type checking: $array = is_array($var) or is_object($var) ? $var : [] ;
  2. Type hinting arraysin methods before using a foreach and specifying return types
  3. Wrapping foreach within if
  4. Using try{}catch(){}blocks
  5. Designing proper code / testing before production releases
  6. To test an array against proper form you could use array_key_existson a specific key, or test the depth of an array (when it is one !).
  7. Always extract your helper methods into the global namespace in a way to reduce duplicate code
  1. 快速类型检查$array = is_array($var) or is_object($var) ? $var : [] ;
  2. 在使用 foreach 和指定返回类型之前在方法中键入提示数组
  3. 将 foreach 包装在 if
  4. 使用try{}catch(){}
  5. 在产品发布之前设计适当的代码/测试
  6. 要根据正确的形式测试数组,您可以array_key_exists在特定键上使用,或测试数组的深度(当它是一个时!)
  7. 始终以减少重复代码的方式将辅助方法提取到全局命名空间中

回答by GigolNet Guigolachvili

Try this:

尝试这个:

//Force array
$dataArr = is_array($dataArr) ? $dataArr : array($dataArr);
foreach ($dataArr as $val) {
  echo $val;
}

;)

;)

回答by boctulus

$values = get_values();

foreach ((array) $values as $value){
  ...
}

Problem is always null and Casting is in fact the cleaning solution.

问题总是无效的,而 Casting 实际上是清洁解决方案。

回答by Edwin Rodríguez

If you're using php7 and you want to handle only undefined errors this is the cleanest IMHO

如果您使用的是 php7 并且只想处理未定义的错误,这是最干净的恕我直言

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}

回答by HongKilDong

More concise extension of @Kris's code

@Kris 代码的更简洁扩展

function secure_iterable($var)
{
    return is_iterable($var) ? $var : array();
}

foreach (secure_iterable($values) as $value)
{
     //do stuff...
}

especially for using inside template code

特别是用于使用内部模板代码

<?php foreach (secure_iterable($values) as $value): ?>
    ...
<?php endforeach; ?>

回答by Your Common Sense

First of all, every variable must be initialized. Always.
Casting is not an option.
if get_values(); can return different type variable, this value must be checked, of course.

首先,每个变量都必须被初始化。总是。
铸造不是一种选择。
如果 get_values(); 可以返回不同类型的变量,当然必须检查这个值。

回答by T30

foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

This doesen't check if it is an array, but skips the loop if the variable is null or an empty array.

这不会检查它是否是数组,但如果变量为 null 或空数组,则跳过循环。