【问题标题】:Invalid argument supplied for foreach()为 foreach() 提供的参数无效
【发布时间】:2011-02-07 11:17:54
【问题描述】:

我经常会处理可以是数组或空变量的数据,并将这些数据提供给foreach

$values = get_values();

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

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

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

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

  • $values 转换为数组
  • $values初始化为数组
  • if 包裹foreach
  • 其他(请提出建议)

【问题讨论】:

  • $values 很可能不是一个数组。

标签: php foreach


【解决方案1】:

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

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

我偏爱的原因是当你没有任何东西可以开始时它不会分配一个空数组。

【讨论】:

  • 或者使用count()判断数组是否为空
  • @Kemo: count() 不可靠。如果你传递count() null,它返回0。如果你传递一个非null,非数组参数,它返回1。因此不可能使用count()来确定变量是否是一个数组,当变量可以是一个空数组,或者是一个包含 1 项的数组。
  • 请注意,有些对象是可迭代的,这个答案不考虑这些。
  • 应该是if (is_array($values) || $values instanceof Traversable)
  • 很遗憾,他没有继续说这肯定不是最有效的方法:D
【解决方案2】:

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

【讨论】:

  • 强制转换是一个选项——如果你使用$array = (array)null;初始化一个数组,你会得到一个空数组。当然这是浪费内存分配;-)
  • +1:从感性的角度阅读,我不在乎语言是否可以没有,变量必须被声明并且不可靠的结果必须 被检查。需要保持开发人员的理智和简短的错误日志。
  • 这是对这个问题的最佳答案。如果您尝试迭代某些东西,那么您显然希望它是可迭代的。强制转换或检查它是否可迭代是浪费时间,因为它所做的只是掩盖变量不包含您认为它所做的事实,这意味着 actual 问题在其他地方你的代码。
【解决方案3】:

我会和安迪做同样的事情,但我会使用“空”功能。

像这样:

if(empty($yourArray))
{echo"<p>There's nothing in the array.....</p>";}
else
{
foreach ($yourArray as $current_array_item)
  {
    //do something with the current array item here
  } 
}

【讨论】:

  • -1, 如果$yourArray = 1; 它将尝试迭代,你会得到错误。 empty() 不是一个合适的测试。
  • @BradKoch 是绝对正确的。 is_array() 是测试 $yourArray 是否为数组的唯一可靠方法。有关 is_array() 为什么不够用的详细信息,请参阅其他答案——foreach 也可以处理迭代器。
【解决方案4】:

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

/**
 * 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...
    }
}

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

编辑:添加Traversable检查

【讨论】:

  • 最佳答案。除了我认为你真的应该检查$var instanceof Traversable。见here。因为例如你可以 foreach 一个 SimpleXMLElement,但它不是 Iterator 或 IteratorAggregate 的实例。
  • 您也许可以删除其他两个类,@Kris。它们现在都扩展了 Traversable 并且似乎是在 5.0.0 中以这种方式诞生的。虽然我对 instanceof 是否总是适用于扩展感到有点怀疑。
  • @BobStein-VisiBone:是的(除了它们是接口,而不是类)但是;我把 Traversable 放在前面,Iterator 和 IteratorAggregate 都不需要验证(这样他们就不会减慢执行速度)。我把它们留在里面是为了使答案尽可能接近我给出的原始答案,并保持其明显/可读性。
  • 我认为添加is_object($var) re 是公平的。 php.net/manual/en/language.oop5.iterations.php
  • @MarkFox:随意,但我故意忽略了它;我从未见过比实现IteratorIteratorAggregate 更好的用途,但这当然只是我的观点,因此是主观的(我从不使用公共字段)。
【解决方案5】:

试试这个:

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

;)

【讨论】:

  • 这不适用于关联数组。is_array 方法总体上更好...而且更简单...
【解决方案6】:

我不确定是否是这种情况,但通常在迁移 wordpress 网站或迁移动态网站时,此问题似乎多次发生。如果是这种情况,请确保您要迁移到的主机使用与旧站点相同的 PHP 版本。

如果您没有迁移您的站点,而这只是一个已经出现的问题,请尝试更新到 PHP 5。这可以解决其中的一些问题。可能看起来像一个愚蠢的解决方案,但对我有用。

【讨论】:

    【解决方案7】:

    似乎也与环境有关:

    我只在开发环境中遇到“invalid argument provided foreach()”错误,但在 prod 中没有(我在服务器上工作,而不是在本地主机上工作)。

    尽管有错误,但 var_dump 表明该数组在那儿很好(在应用程序和开发人员的情况下)。

    foreach ($array as $subarray) 周围的if (is_array($array)) 解决了这个问题。

    抱歉,我无法解释原因,但由于我花了一段时间才找到解决方案,所以我想更好地分享这个作为观察结果。

    【讨论】:

      【解决方案8】:

      这个怎么样?更干净,而且都在单行中。

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

      【讨论】:

      • 这是唯一对我有用的东西。由于某种原因,PHP 不相信我构建的多维数组实际上是一个数组数组。
      • 这里也一样,对于包含数组或空值的数组来说,这是一个非常好的修复。如果数据为空,只需在 foreach 循环中添加一个测试即可继续。
      • 解决了我的问题。谢谢!
      • 出色的代码,使用带有复选框的 $_POST 跳过了 if、else 数组和非数组值!
      • 注意:虽然外观漂亮并解决了无效的 foreach 警告,但如果未以任何方式设置变量,此方法将返回未定义变量警告。使用isset()is_array() 或两者都使用,完全取决于您的场景等。
      【解决方案9】:

      foreach() 显示推文提供的警告参数无效。 去/wp-content/plugins/display-tweets-php。 然后在第591行插入这段代码,就可以完美运行了。

      if (is_array($tweets)) {
          foreach ($tweets as $tweet) 
          {
              ...
          }
      }
      

      【讨论】:

      • 太棒了!这应该是公认的解决方案。在我的情况下,我添加了这个:if (is_array($_POST['auto'])){ // code }
      【解决方案10】:

      @Kris's code的更简洁扩展

      function secure_iterable($var)
      {
          return is_iterable($var) ? $var : array();
      }
      
      foreach (secure_iterable($values) as $value)
      {
           //do stuff...
      }
      

      特别是使用内部模板代码

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

      【讨论】:

      • 你不是说return is_iterable($var) ? $var : array($var);吗?
      【解决方案11】:

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

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

      例如将布尔值强制转换为数组 (array)boolNOT 会生成一个空数组,但会生成一个数组,其中一个元素包含作为 int 的布尔值:[0=&gt;0][0=&gt;1]

      I wrote a quick test to present this problem。 (这里是backup Test,以防第一个测试网址失败。)

      包括以下测试:nullfalsetrueclassarrayundefined


      在 foreach 中使用之前始终测试您的输入。建议:

      1. Quick type checking: $array = is_array($var) or is_object($var) ? $var : [] ;
      2. Type hinting arrays 在使用 foreach 和 specifying return types 之前的方法中
      3. 在 if 中包装 foreach
      4. 使用try{}catch(){}
      5. 在产品发布之前设计正确的代码/测试
      6. 要根据正确的形式测试数组,您可以在特定键 or test the depth of an array (when it is one !) 上使用 array_key_exists
      7. 始终将帮助方法提取到全局命名空间中,以减少重复代码

      【讨论】:

        【解决方案12】:
        foreach ($arr ?: [] as $elem) {
            // Do something
        }
        

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

        从 PHP 7.0 更新你应该使用null coalescing operator:

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

        这将解决评论中提到的警告(here 一个方便的表格,用于比较 ?:?? 的输出)。

        【讨论】:

        • 这会在 $arr 无效时产生 PHP 警告“不能将标量值用作数组”。您可以事先创建一个空数组,然后引用它而不是 []。但这有时会在使用 $elem 作为 "&$elem" 之类的引用时产生单独的问题,因此我现在不推荐任何一种方法。
        【解决方案13】:

        如果您在 foreach 循环中将数组设置为 null,则会出现此通知的例外情况

        if (is_array($values))
        {
            foreach ($values as $value)
            {
                $values = null;//WARNING!!!
            }
        }
        

        【讨论】:

          【解决方案14】:
          $values = get_values();
          
          foreach ((array) $values as $value){
            ...
          }
          

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

          【讨论】:

            【解决方案15】:

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

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

            【讨论】:

              【解决方案16】:

              我将使用emptyissetis_array 的组合作为

              $array = ['dog', 'cat', 'lion'];
              
              if (!empty($array) && isset($array) && is_array($array) {
                  //loop
                  foreach ($array as $values) {
                      echo $values; 
                  }
              }
              

              【讨论】:

                【解决方案17】:

                使用 is_array 函数,当你将数组传递给 foreach 循环时。

                if (is_array($your_variable)) {
                  foreach ($your_variable as $item) {
                   //your code
                }
                }
                

                【讨论】:

                  【解决方案18】:

                  这个解决方案怎么样:

                  $type = gettype($your_iteratable);
                  $types = array(
                      'array',
                      'object'
                  );
                  
                  if (in_array($type, $types)) {
                      // foreach code comes here
                  }
                  

                  【讨论】:

                    【解决方案19】:

                    如果get_value() 为空,如何将空数组定义为备用?
                    我想不出最短的方法。

                    $values = get_values() ?: [];
                    
                    foreach ($values as $value){
                      ...
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 2011-05-17
                      相关资源
                      最近更新 更多