Указан неверный аргумент для foreach () - PullRequest
269 голосов
/ 13 апреля 2010

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

$values = get_values();

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

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

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

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

  • Приведение $values к массиву
  • Инициализация $values в массив
  • Упаковка foreach с if
  • Другое (просьба предложить)

Ответы [ 19 ]

462 голосов
/ 13 апреля 2010

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

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

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

94 голосов
/ 08 апреля 2015

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

foreach ((array) $items as $item) {
 // ...
 }
40 голосов
/ 27 марта 2013

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

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

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

13 голосов
/ 26 сентября 2015

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

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

например. приведение логического значения к массиву (array)bool приведет к тому, что NOT приведет к пустому массиву, но массиву с одним элементом, содержащим логическое значение типа 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. Всегда извлекайте ваши вспомогательные методы в глобальное пространство имен, чтобы уменьшить количество дублирующихся кодов
8 голосов
/ 13 июня 2014

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

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

;)

4 голосов
/ 02 марта 2016
$values = get_values();

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

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

3 голосов
/ 23 апреля 2015

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

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 голосов
/ 13 апреля 2010

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

2 голосов
/ 09 августа 2016

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

$array = [1,2,3,4];
foreach ( $array ?? [] as $item ) {
  echo $item;
}
2 голосов
/ 18 декабря 2015
foreach ($arr ? $arr : [] as $elem) {
    // Does something 
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...