Недопустимый аргумент для foreach()

мне часто случается обрабатывать данные, которые могут быть массивом или нулевой переменной, и кормить некоторые foreach С этими данными.

$values = get_values();

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

когда вы кормите foreach данными, которые не являются массивом, вы получаете предупреждение:

предупреждение: недопустимый аргумент для foreach () в [...]

предполагая, что это не возможно, чтобы рефакторинг get_values() функция всегда возвращать массив (обратная совместимость, недоступный исходный код, независимо от другой причины), мне интересно, какой самый чистый и эффективный способ избежать этих предупреждений:

  • литье $values в массиве
  • инициализации $values в массиве
  • упаковка foreach С if
  • другое (пожалуйста, предложите)

18 ответов


лично я считаю, что это самый чистый - не уверен, что это самый эффективный, ум!

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

причина моего предпочтения заключается в том, что он не выделяет пустой массив, когда вам все равно нечего начинать.


Как насчет этого? намного чище и все в одну строку.

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

Я обычно использую конструкцию, подобную этой:

/**
 * 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 из памяти.

Edit: добавил проходимым Регистрация


пожалуйста, не зависит от литья в качестве решения, даже если другие предлагают это как допустимый вариант для предотвращения ошибки, это может привести к другому.

имейте в виду: если вы ожидаете, что будет возвращена определенная форма массива, это может привести к сбою. Для этого требуется больше проверок.

Е. Г. кастинг логическое массива (array)bool, будет не результат в пустой массив, а массив с одним элементом содержит логическое значение в виде int:[0=>0] или [0=>1].

я написал небольшой тест, чтобы представить эту проблему. (Вот резервное копирование тест в случае сбоя первого тестового url-адреса.)

включены тесты для: null, false, true, a class, an array и undefined.


всегда проверяйте свой ввод перед его использованием в foreach. Предложения:

  1. быстрая введите проверка: $array = is_array($var) or is_object($var) ? $var : [] ;
  2. введите массивы намеков в методах перед использованием foreach и С указанием типов возвращаемых
  3. обертывание foreach внутри if
  4. используя try{}catch(){} блоки
  5. проектирование правильного кода / тестирование перед выпуском продукции
  6. чтобы проверить массив на правильную форму, вы можете использовать array_key_exists на определенном ключе,или проверьте глубину массива (когда он один !).
  7. всегда извлекать вспомогательные методы в глобальное пространство имен таким образом, чтобы уменьшить дублирование кода

попробуйте это:

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

;)


$values = get_values();

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

проблема всегда нулевая, и литье на самом деле является решением для очистки.


во-первых, каждая переменная должна быть инициализирована. Всегда.
Кастинг не вариант.
если get_values (); может возвращать переменную другого типа, это значение, конечно, должно быть проверено.


более краткое расширение @Крис кода

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

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

Это не проверяет, является ли это массивом, но пропускает цикл, если переменная равна null или пустому массиву.


Если вы используете php7 и хотите обрабатывать только неопределенные ошибки, это самый чистый IMHO

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

Я не уверен, что это так, но эта проблема, похоже, возникает несколько раз при миграции сайтов wordpress или миграции динамических сайтов в целом. Если это так, убедитесь, что хостинг, на который вы переходите, использует ту же версию PHP, что и ваш старый сайт.

Если вы не переносите свой сайт, и это просто проблема, которая возникла, попробуйте обновить до PHP 5. Это решает некоторые из этих проблем. Может показаться глупым решением, но сделал трюк для меня.


исключительный случай для этого уведомления возникает, если вы устанавливаете array в null внутри цикла foreach

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

Как насчет такого решения:

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

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

Кажется, также существует отношение к окружающей среде:

у меня была ошибка "недопустимый аргумент, предоставленный foreach ()" только в среде dev, но не в prod (я работаю на сервере, а не на localhost).

несмотря на ошибку, var_dump указал, что массив был хорошо там (в обоих случаях app и dev).

на if (is_array($array)) вокруг foreach ($array as $subarray) решена проблема.

Извините, что я не могу объяснить причину, но так как мне потребовалось некоторое время, чтобы я подумал, что лучше поделиться этим наблюдением.


Я буду использовать комбинацию empty, isset и is_array как

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

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

используйте функцию is_array, когда вы передадите массив в цикл foreach.

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

предупреждение недопустимый аргумент, предоставленный для твитов foreach (). перейдите в раздел " / wp-content / plugins / display-tweets-php ". Затем вставьте этот код в строку номер 591, он будет работать отлично.

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

Я бы сделал то же самое, что и Энди, но я бы использовал функцию "пустой".

вот так:

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