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

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

$values = get_values();

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

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

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

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

  • Литье $values в массив
  • Инициализация $values для массива
  • Обтекание foreach с помощью if
  • Другое (пожалуйста, предложите)

Ответ 1

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

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

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

Ответ 2

Как насчет этого? много чистых и все в одной линии.

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

Ответ 3

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

/**
 * 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 проверить

Ответ 4

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

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

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

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

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


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

Ответ 5

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

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

;)

Ответ 6

$values = get_values();

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

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

Ответ 7

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

Ответ 8

Более сжатое расширение @Kris 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; ?>

Ответ 9

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

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

Ответ 10

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

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

Ответ 11

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

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

Ответ 12

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

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

Ответ 13

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

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

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

Ответ 14

Похоже, что есть отношение к среде:

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

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

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

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

Ответ 15

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

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

Ответ 16

Я буду использовать комбинацию пустых, isset и is_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

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

так:

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