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


304

我经常碰巧处理可以是数组或null变量的数据,并foreach用这些数据提供一些数据。

$values = get_values();

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

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

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

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

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

这很有可能$values不是数组。
Bhargav Nanekalva '17

Answers:


509

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

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

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


4
或使用count()判断数组是否不为空
Kemo

76
@Kemo:count()不可靠。如果传递count()null,则返回0。如果传递非null,非数组参数,则返回1。因此,count()当变量可能为空数组时,无法使用该变量来确定其是否为数组,或者包含1个项目的数组。
安迪·谢拉姆

12
请注意,某些对象是可迭代的,并且此答案不能解决这些问题。
Brad Koch

32
应该是if (is_array($values) || $values instanceof Traversable)
鲍勃·斯坦

3
可惜他没有继续说那不是肯定是最有效的,但是:D
GuiPrá15'Feb

116

这个怎么样?更清洁,所有都在单行中。

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

7
这是唯一对我有用的东西。由于某种原因,PHP不相信我构建的多维数组实际上是数组的数组。
贾斯汀

1
同样,对于包含数组或空值的数组,这是一个非常好的解决方案。如果数据为空,只需在foreach循环中添加一个测试即可继续。
Lizardx

解决了我的问题。谢谢!
Hitesh

1
出色的代码,使用$ _POST和checkbox跳过了if和else数组和无数组值!
Yann Chabot,

2
注意:虽然外观漂亮并解决了无效的foreach警告,但如果未以任何方式设置变量,则此方法将返回未定义的变量警告。使用isset()is_array()或两者兼而有之,完全取决于您的方案等
詹姆斯

42

我通常使用类似于以下的构造:

/**
 * 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中。

编辑:添加了遍历检查


3
最佳答案。除了我认为你应该真的检查一下$var instanceof Traversable。看这里。因为例如您可以foreach一个SimpleXMLElement,但是它不是Iterator或IteratorAggregate的实例。
鲍勃·斯坦

2
您也许可以删除其他两个类@Kris。它们现在都扩展了Traversable,并且似乎是在5.0.0中诞生的。尽管我对instanceof是否始终适用于extended感到有点怀疑。
鲍勃·斯坦

1
@ BobStein-VisiBone:是的(除了它们是接口,不是类),但是;我将Traversable放在那些之前,Iterator和IteratorAggregate都不需要验证(这样,它们就不会减慢执行速度)。我将它们留在原处,以使答案尽可能接近我给出的原始答案,并使其清晰可见。
克里斯(Kris)2014年

2
我认为添加is_object($var)re 是公平的。php.net/manual/en/language.oop5.iterations.php
马克·福克斯

1
@MarkFox:随意,但是我有意省略了它;我从来没有见过通过实现Iterator或可以更好地使用它的用途IteratorAggregate,但这当然只是我的意见,因此是主观的(我从未使用过公共领域)。
克里斯(Kris)

15

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

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

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

我写了一个快速测试来介绍这个问题。(这里是备用测试,以防第一个测试URL失败。)

包括用于测试:nullfalsetrue,一class,一arrayundefined


在foreach中使用输入之前,请务必先对其进行测试。意见建议:

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

8

尝试这个:

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

;)


1
is_array方法总体上更好,而且更容易...
AO_14年

4
$values = get_values();

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

问题始终是空的,而铸造实际上是清洁的解决方案。


3

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


强制转换是一种选择-如果使用初始化数组,$array = (array)null;则会得到一个空数组。当然,这浪费了内存分配;-)
Andy Shellam

2
+1:从感性的角度看,我不在乎语言是否可以做到,必须声明变量,并且必须检查不可靠的结果。需要使开发人员保持理智,并且错误日志要简短。
克里斯(Kris)

3

@Kris代码的更简洁的扩展

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; ?>

2
不是return is_iterable($var) ? $var : array($var);
SQB


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

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


1

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

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



1

该解决方案如何:

$type = gettype($your_iteratable);
$types = array(
    'array',
    'object'
);

if (in_array($type, $types)) {
    // foreach code comes here
}

1

foreach()显示鸣叫提供了警告无效的参数。去/wp-content/plugins/display-tweets-php。然后将此代码插入第591行,它将完美运行。

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

太棒了!那应该是公认的解决方案。就我而言,我添加了以下内容:if (is_array($_POST['auto'])){ // code }
Jodyshop '19

0

似乎也与环境有关:

我只有在开发环境中才有那个“无效的参数提供了foreach()”错误,但在prod中却没有(我在服务器上工作,而不是localhost)。

尽管有错误,但var_dump仍指示该阵列位于该位置(在app和dev情况下)。

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

抱歉,我无法解释原因,但是由于花了我一段时间才能找到解决方案,因此我认为最好将其分享为观察结果。


0

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

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

0

如果将空数组定义为后备,该get_value()怎么办?
我想不出最短的方法。

$values = get_values() ?: [];

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

0

我将使用的组合emptyissetis_array作为

$array = ['dog', 'cat', 'lion'];

if (!empty($array) && isset($array) && is_array($array) {
    //loop
    foreach ($array as $values) {
        echo $values; 
    }
}

-3

我会做和Andy一样的事情,但是我会使用“空”功能。

像这样:

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
  } 
}

3
-1,如果$yourArray = 1;它将尝试进行迭代,则您将得到错误。 empty()这不是合适的测试。
布拉德·科赫

@BradKoch绝对正确。is_array()是测试$ yourArray是否为数组的唯一可靠方法。有关is_array()不足的详细信息,请参见其他答案-foreach也可以处理迭代器。
cgeisel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.