为foreach()提供的参数无效

Rob*_*loi 282 php foreach

我经常遇到处理数据的问题,foreach这些数据既可以是数组也可以是null变量,并且可以为这些数据提供一些数据.

$values = get_values();

foreach ($values as $value){
  ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 投射$values到阵列
  • 初始化$values为数组
  • foreach用一个包裹着if
  • 其他(请建议)

And*_*lam 481

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

if (is_array($values) || is_object($values))
{
    foreach ($values as $value)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我偏好的原因是,当你无论如何都没有任何东西时,它不会分配一个空数组.

  • @Kemo:`count()`不可靠.如果你传递`count()`null,它返回0.如果你传递一个非null,非数组参数,它返回1.因此,不可能使用`count()`来确定变量是否是一个数组当变量可以是空数组或包含1个项目的数组时. (74认同)
  • 应该是`if(is_array($ values)|| $ values instanceof Traversable)`. (29认同)
  • 请注意,某些对象是可迭代的,并且此答案不考虑这些. (12认同)
  • 或者使用count()来确定数组是否为空 (4认同)
  • 如今,“is_iterable()”就是它所在的位置 (4认同)
  • 令人遗憾的是,他没有继续说这不是最有效的,但是:D (3认同)

小智 102

这个怎么样?更清洁,所有在一条线.

foreach ((array) $items as $item) {
 // ...
 }
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一对我有用的东西.出于某种原因,PHP不相信我构建的多维数组实际上是一个数组数组. (6认同)
  • 注意:虽然美观并且解析了无效的foreach警告,但如果未以任何方式设置变量,此方法将返回未定义的变量警告.使用`isset()`或`is_array()`或两者,完全取决于你的场景等. (2认同)

Kri*_*ris 41

我通常使用类似于这样的结构:

/**
 * 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...
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此特定版本未经过测试,直接从内存中输入SO.

编辑:添加了Traversable检查

  • 最佳答案.除了我认为你应该真的检查`$ var instanceof Traversable`.见[here](http://www.php.net/manual/en/class.traversable.php).因为例如你可以预见[SimpleXMLElement](http://www.php.net/manual/en/class.simplexmlelement.php),但它不是Iterator或IteratorAggregate的实例. (3认同)
  • 您可以删除其他两个类,@ Kris.它们现在都延伸**[Traversable](http://www.php.net/manual/en/class.traversable.php)**,似乎在5.0.0中就这样诞生了.虽然我对是否总是适用于延伸而感到很怀疑. (2认同)
  • 我认为添加`is_object($ var)`re是公平的.http://php.net/manual/en/language.oop5.iterations.php (2认同)

AAR*_*RTT 14

请不要依赖于转换作为解决方案,即使其他人建议将其作为防止错误的有效选项,也可能会导致另一个错误.

请注意:如果您希望返回特定形式的数组,则可能会失败.需要更多检查.

例如(array)bool,将一个布尔值转换为数组,不会产生空数组,而是一个数组,其中一个元素包含布尔值作为int:[0=>0][0=>1].

我写了一个快速测试来介绍这个问题.(如果第一个测试网址失败,这是备份测试.)

包括用于测试:null,false,true,一class,一arrayundefined.


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

  1. 快速类型检查:$array = is_array($var) or is_object($var) ? $var : [] ;
  2. 在使用foreach并指定返回类型之前,在方法中键入提示数组
  3. 在fore中包装foreach
  4. 使用try{}catch(){}
  5. 在生产发布之前设计适当的代码/测试
  6. 要针对正确的形式测试数组,您可以使用array_key_exists特定的键,或测试数组的深度(当它是一个!).
  7. 始终以减少重复代码的方式将辅助方法提取到全局命名空间中


You*_*nse 8

上面提供的所有答案本质上只是错误抑制。

您的 PHP 告诉您正在尝试使用类型不正确的变量,并且可能存在错误。但提供的所有答案都只是忽略了此消息。

最好的办法是在使用之前初始化每个变量。并使返回类型严格且明确。您必须问自己,为什么get_values()返回数组以外的任何内容?如果没有找到数据,为什么不能只返回一个空数组?当然可以。

  • +1:从情感的角度来看,我不在乎语言是否可以没有,变量_必须_被声明并且不可靠的结果_必须_被检查。需要让开发人员保持理智并且错误日志简短。 (3认同)

Gig*_*ili 8

试试这个:

//Force array
$dataArr = is_array($dataArr) ? $dataArr : array($dataArr);
foreach ($dataArr as $val) {
  echo $val;
}
Run Code Online (Sandbox Code Playgroud)

;)


T30*_*T30 6

foreach ($arr ?: [] as $elem) {
    // Do something
}
Run Code Online (Sandbox Code Playgroud)

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

从 PHP 7.0 更新,您应该使用null 合并运算符

foreach ($arr ?? [] as $elem) {
    // Do something
}
Run Code Online (Sandbox Code Playgroud)

这将解决评论中提到的警告(这里?:有一个方便的比较和输出表??)。


boc*_*lus 6

$values = get_values();

foreach ((array) $values as $value){
  ...
}
Run Code Online (Sandbox Code Playgroud)

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


Edw*_*uez 5

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

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


Tec*_*ngo 5

自 PHP >= 7.1.0 使用is_iterable

https://www.php.net/manual/en/function.is-iterable.php

if (is_iterable($value)) {
    foreach ($value as $v) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)