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


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

$values = get_values();

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

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

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

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

  • Приведение $values к массиву
  • Инициализация $values в массив
  • Обертывание foreach с помощью if
  • Другое (пожалуйста, предложите)
 248
Author: Geoffrey Hale, 2010-04-13

18 answers

Лично я нахожу это наиболее чистым - не уверен, что это наиболее эффективно, имейте в виду!

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

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

 424
Author: Andy Shellam, 2015-10-27 20:57:40

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

foreach ((array) $items as $item) {
 // ...
 }
 76
Author: Ajith R Nair, 2015-04-08 17:08:27

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

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

Редактировать: добавлен Проходимый проверка

 37
Author: Kris, 2015-05-25 13:47:49

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

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

Например, приведение логического значения к массиву (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. Обертывание для каждого в пределах if
  4. Использование try{}catch(){} блоков
  5. Разработка правильного кода/тестирование перед выпуском продукции
  6. Чтобы проверить массив на соответствие правильной форме, вы можете использовать array_key_exists для определенного ключа, или проверить глубину массива (когда он один !).
  7. Всегда извлекайте свои вспомогательные методы в глобальное пространство имен, чтобы уменьшить количество повторяющихся кодов
 13
Author: AARTT, 2017-05-23 12:10:54

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

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

;)

 6
Author: GigolNet Guigolachvili, 2018-07-30 12:52:18
$values = get_values();

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

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

 4
Author: boctulus, 2016-03-02 16:59:44

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

 3
Author: Your Common Sense, 2010-04-13 14:11:25

Более краткое расширение кода @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; ?>
 3
Author: HongKilDong, 2017-05-23 11:33:24
foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

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

 2
Author: T30, 2016-07-14 02:41:50

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

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}
 2
Author: Edwin Rodríguez, 2016-08-09 15:27:03

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

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

 1
Author: Erik, 2014-07-12 13:16:28

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

if (is_array($values))
{
    foreach ($values as $value)
    {
        $values = null;//WARNING!!!
    }
}
 1
Author: Farid Movsumov, 2016-01-18 09:24:52

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

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

if (in_array($type, $types)) {
    // foreach code comes here
}
 1
Author: Julian, 2017-11-01 12:04:11

По-видимому, также существует связь с окружающей средой:

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

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

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

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

 0
Author: araldh, 2015-02-22 11:36:42

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

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

if(!empty($array)  && isset($array)  && is_array($array){
//loop
foreach ($array as $values) {
echo $values; 
}
}
 0
Author: Akintunde-Rotimi, 2017-10-06 17:10:50

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

if (is_array($your_variable)) {
  foreach ($your_variable as $item) {
   //your code
}
}
 0
Author: Super Model, 2017-10-21 21:46:43

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

if (is_array($tweets)){  
        foreach ( $tweets as $tweet ) 
    {
        ...
    }
}
 0
Author: Saad Khanani, 2018-05-03 02:59:48

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

Вот так:

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
Author: as_bold_as_love, 2012-09-30 17:40:04