2010-04-13 5 views
208

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

$values = get_values(); 

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

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

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

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

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

Это очень возможно '$ values' не является массивом. –

ответ

368

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

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

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

+2

Или используйте count(), чтобы выяснить, не массив ли пуст – Kemo

+61

@Kemo: 'count()' не является надежным. Если вы передадите 'count()' null, он возвращает 0. Если вы передадите ему ненулевой аргумент без массива, он возвращает 1. Поэтому невозможно использовать 'count()', чтобы определить, является ли переменная массивом когда переменная может быть пустым массивом или массивом, содержащим 1 элемент. –

+10

Обратите внимание, что некоторые объекты итерабельны, и этот ответ не учитывает их. –

3

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

+0

Кастинг - это опция - если вы инициализируете массив, используя' $ array = (array) null, 'вы получаете пустой массив. Конечно, это пустая трата памяти ;-) –

+1

+1: читайте с сентиментальной точки зрения, меня не волнует, если язык может обойтись, переменные _MUST_ будут объявлены и недостоверны результаты _MUST_. Требуется, чтобы разработчик (s) был нормальным, а журналы ошибок были короткими. – Kris

-3

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

так:

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

-1, Если '$ yourArray = 1;' будет пытаться выполнить итерацию, и вы получите ошибку. 'empty()' не является подходящим тестом. –

+0

@BradKoch абсолютно прав. is_array() является единственным надежным способом проверки того, является ли $ yourArray массивом. См. Другие ответы, чтобы узнать, почему is_array() недостаточно - foreach также может обрабатывать итераторы. – cgeisel

33

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

/** 
* 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 проверка

+1

Лучший ответ. Кроме того, я думаю, вы действительно должны проверить, есть ли '$ var instanceof Traversable'. См. [Здесь] (http://www.php.net/manual/en/class.traversable.php). Например, вы можете выделить [SimpleXMLElement] (http://www.php.net/manual/en/class.simplexmlelement.php), но это не экземпляр ни Iterator, ни IteratorAggregate. –

+0

@ BobStein-VisiBone: Я полностью согласен, добавил. – Kris

+0

Возможно, вам удастся удалить два других класса, @Kris. Они оба теперь расширяются ** [Traversable] (http://www.php.net/manual/en/class.traversable.php) ** и, похоже, были рождены таким образом в 5.0.0. Хотя я чувствую крошечное сомнение относительно того, всегда ли экземпляр всегда применяется к продолжениям. –

4

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

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

;)

+0

Это не сработает с ассоциативными массивами .. Метод is_array в целом лучше ... и проще ... –

1

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

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

0

Там, кажется, также быть отношение к окружающей среде:

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

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

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

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

64

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

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

Это единственное, что сработало для меня. По какой-то причине PHP не верил, что многомерный массив, который я построил, фактически был массивом массивов. – Justin

+1

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

+0

Решил мою проблему. Благодаря! – Hitesh

0

предупреждение неверный аргумент, предоставленный для твитов foreach(). Перейти к./WP-содержание/плагины/дисплей-твиты-PHP

вставки этот Coad на номере строки 591. Он будет работать идеально

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

Более краткое расширение @Kris's 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; ?> 
+2

Вы не имеете в виду 'return is_iterable ($ var)? $ var: array ($ var); '? – SQB

10

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

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

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

I wrote a quick test to present this problem. (Вот в случае первый тест URL проваливает backup Test.)

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


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

  1. Quick type checking: $array = is_array($var) or is_object($var) ? $var : [] ;
  2. Type hinting arrays методов перед использованием Еогеасп и specifying return types
  3. Упаковочная Еогеасп в случае
  4. Использование try{}catch(){} блоков
  5. Проектирование правильного кода/тестирование до производственных выпусков
  6. Чтобы проверить массив на правильную форму, вы можете использовать array_key_exists o n конкретный ключ, or test the depth of an array (when it is one !).
  7. Всегда извлечь ваши вспомогательные методы в глобальное пространство имен таким образом, чтобы уменьшить дублирование кода
2
foreach ($arr ? $arr : [] as $elem) { 
    // Does something 
} 

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

1

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

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

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

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

2

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

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

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

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

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

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

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

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

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

if (in_array($type, $types)) { 
    // foreach code comes here 
} 
Смежные вопросы