it-swarm.com.ru

В foreach указан неверный аргумент ()

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

$values = get_values();

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

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

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

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

  • Приведение $values к массиву
  • Инициализация $values для массива
  • Обертывание foreach с if
  • Другое (пожалуйста, предложите)
252
Roberto Aloi

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

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

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

442
Andy Shellam

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

foreach ((array) $items as $item) {
 // ...
 }
83
Ajith R Nair

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

/**
 * 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: добавлено Traversable check

39
Kris

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

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

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

Я написал быстрый тест, чтобы представить эту проблему . (Вот Резервный тест на случай, если первый тестовый URL не пройден.)

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


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

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

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

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

;)

6
GigolNet Guigolachvili
$values = get_values();

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

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

4
boctulus

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

3
Your Common Sense

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

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
HongKilDong

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

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}
2
Edwin Rodríguez
foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

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

2
T30

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

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

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

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

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

1
Erik

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

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

Как насчет определения пустого массива как запасного, если get_value() пуст?
Я не могу придумать кратчайшего пути.

$values = get_values() ?: [];

foreach ($values as $value){
  ...
}
0
Quentin Veron

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

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

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

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

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

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

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

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

0
araldh

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

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

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

if (is_array($tweets)){  
        foreach ( $tweets as $Tweet ) 
    {
        ...
    }
}
0
Saad Khanani