foreach ()에 잘못된 인수가 제공되었습니다.


304

배열 또는 null 변수 일 수있는 데이터를 처리 foreach하고 이러한 데이터로 일부를 제공하는 것이 종종 발생합니다 .

$values = get_values();

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

배열이 아닌 데이터를 foreach에 공급하면 경고가 표시됩니다.

경고 : [...]의 foreach ()에 잘못된 인수가 제공되었습니다.

get_values()항상 배열을 반환하도록 함수 를 리팩터링 할 수 없다고 가정하면 (이전의 호환성, 사용 가능한 소스 코드 등 다른 이유가 무엇이든), 이러한 경고를 피하는 가장 깨끗하고 효율적인 방법이 무엇인지 궁금합니다.

  • $values배열로 캐스팅
  • $values배열로 초기화
  • 포장 foreach과를if
  • 기타 (제발 제안)

$values배열이 아닌 가능성이 높습니다 .
Bhargav Nanekalva

답변:


509

개인적으로 나는 이것이 가장 깨끗하다고 ​​생각합니다. 그것이 가장 효율적인지, 마음인지 확실하지 않습니다!

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

내가 선호하는 이유는 어쨌든 시작할 것이 없을 때 빈 배열을 할당하지 않기 때문입니다.


4
또는 count ()를 사용하여 배열이 비어 있지 않은지 알아냅니다.
Kemo

76
@Kemo : count()신뢰할 수 없습니다. 당신이 전달하는 경우 count()는 null를, 당신이 그것을 통과하면 0을 반환 null 이외는, 배열이 아닌 인수, 그것은 반환 1. 따라서 사용 불가능 count(), 변수가 빈 상태 (empty)의 배열이 될 수있을 때 변수가 배열인지 확인하거나 1 개의 항목을 포함하는 배열
Andy Shellam

12
일부 객체는 반복 가능 하며이 답변은 해당 객체를 설명하지 않습니다.
Brad Koch

32
이어야 if (is_array($values) || $values instanceof Traversable)합니다.
Bob Stein

3
비록 그것이 가장 효율적이지는 않다고 말하지 않은 것은 부끄러운 일입니다. : D
Gui Prá

116

이건 어때? 더 깨끗하고 한 줄로 모두.

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

7
이것이 나를 위해 일한 유일한 것입니다. 어떤 이유로 PHP는 내가 만든 다차원 배열이 실제로 배열의 배열이라고 믿지 않았습니다.
Justin

1
여기에서도 마찬가지입니다. 이것은 배열 또는 null 값을 포함하는 배열에 대한 매우 좋은 수정입니다. 데이터가 null이면 foreach 루프에 테스트를 추가하기 만하면됩니다.
Lizardx

내 문제를 해결했다. 감사!
Hitesh

1
화려한 코드는 $ _POST를 확인란과 함께 사용하여 배열 및 none-array 값의 경우 if를 건너 뛰었습니다.!
Yann Chabot

2
참고 : 아름답게 보이고 잘못된 foreach 경고를 해결하는 동안이 방법은 변수가 설정되지 않은 경우 정의되지 않은 변수 경고를 반환합니다. 사용 isset()하거나 is_array()또는 둘 모두 완전히 등 시나리오에 따라
제임스

42

나는 보통 다음과 비슷한 구문을 사용합니다.

/**
 * 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로 직접 입력되었습니다.

편집 : 순회 검사 추가


3
가장 좋은 답변입니다. 당신이 정말로 확인해야한다고 생각하지 않습니다 $var instanceof Traversable. 여기를 참조 하십시오 . 예를 들어 SimpleXMLElement를 foreach 할 수 있지만 Iterator 또는 IteratorAggregate의 인스턴스가 아닙니다.
Bob Stein

2
다른 두 클래스 인 @Kris를 제거 할 수 있습니다. 그들은 모두 Traversable을 확장 하고 5.0.0에서 그렇게 태어난 것으로 보입니다. instanceof가 항상 확장에 적용되는지 여부에 대해서는 약간의 의심이 있습니다.
Bob Stein

1
@ BobStein-VisiBone : yes (클래스가 아닌 인터페이스 인 경우는 제외) 그러나; Traversable을 그 앞에 두었습니다 .Iterator와 IteratorAggregate는 검증을 필요로하지 않습니다 (이렇게하면 실행 속도가 느려지지 않습니다). 나는 원래 답변에 가능한 한 가깝게 답변을 유지하고 명확하게 읽을 수 있도록 유지했습니다.
Kris

2
나는 is_object($var)re 를 추가하는 것이 공정하다고 생각합니다 . php.net/manual/en/language.oop5.iterations.php
Mark Fox

1
@MarkFox : 자유롭게 느끼지만, 의도적으로 제외했습니다. 더 나은 구현하여 제공되지 않은 그것을 위해 사용 본 적이 Iterator또는 IteratorAggregate하지만, 물론 그냥 내 의견 및 그 주관의의 (나는 공공 필드를 사용하지 않습니다를).
Kris

15

다른 사람이 오류를 방지하기 위해 유효한 옵션으로 제안하더라도 다른 솔루션 을 사용할 수 있지만 솔루션으로 캐스트하지 마십시오 .

주의 : 특정 형식의 배열이 반환 될 것으로 예상되면 실패 할 수 있습니다. 이에 대한 추가 점검이 필요합니다.

예는 배열에 부울 캐스팅 (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

이 시도:

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

;)


1
이것은 연관 배열에서는 잘 작동하지 않습니다. is_array 방법이 전반적으로 더 좋고 ... 더 쉽습니다 ...
AO_

4
$values = get_values();

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

문제는 항상 null이며 주조는 실제로 세척액입니다.


3

우선, 모든 변수를 초기화해야합니다. 항상.
캐스팅은 옵션이 아닙니다.
get_values ​​() 인 경우; 다른 유형 변수를 반환 할 수 있으므로 물론이 값을 확인해야합니다.


캐스팅은 옵션입니다- $array = (array)null;빈 배열을 사용하여 배열을 초기화하면 옵션 입니다. 물론 그것은 메모리 할당의 낭비입니다 ;-)
Andy Shellam

2
1 : 변수없이 언어가 할 수있는 경우보기의 감상적인 관점에서 읽기, 난 상관 없어 반드시 선언하고 신뢰할 수없는 결과를 반드시 확인. 개발자를 제자리에 유지하고 오류 로그를 짧게 유지해야합니다.
Kris

3

@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; ?>

2
당신은 의미하지 return is_iterable($var) ? $var : array($var);않습니까?
SQB

3

php7을 사용 중이고 정의되지 않은 오류 만 처리하려는 경우 가장 깨끗한 IMHO입니다.

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

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

이것은 배열인지 확인하지 않지만 변수가 null이거나 빈 배열이면 루프를 건너 뜁니다.


1

이것이 사실인지 확실하지 않지만 워드 프레스 사이트를 마이그레이션하거나 동적 사이트를 일반적으로 마이그레이션 할 때이 문제가 여러 번 발생하는 것 같습니다. 이 경우 마이그레이션하려는 호스팅이 이전 사이트에서 사용하는 것과 동일한 PHP 버전을 사용해야합니다.

사이트를 마이그레이션하지 않고이 문제 만 발생하면 PHP 5로 업데이트하십시오.이 문제 중 일부를 처리합니다. 어리석은 해결책처럼 보이지만 나를 위해 속임수를 쓰십시오.


1

foreach 루프 내에서 배열을 null로 설정하면이 알림의 예외가 발생합니다.

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

1

이 솔루션은 어떻습니까?

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

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

1

foreach()디스플레이 트윗에 경고가 잘못된 인수가 제공되었습니다 . 로 이동하십시오 /wp-content/plugins/display-tweets-php. 그런 다음이 코드를 줄 번호 591에 삽입하면 완벽하게 실행됩니다.

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

대박! 그것이 받아 들여진 해결책이어야합니다. 내 경우에 나는 이것을 추가했다 :if (is_array($_POST['auto'])){ // code }
Jodyshop

0

환경과도 관련이있는 것 같습니다.

dev 환경에서만 "잘못된 인수가 foreach ()"오류가 발생했지만 prod에는 없습니다 (localhost가 아닌 서버에서 작업하고 있습니다).

오류에도 불구하고 var_dump는 배열이 적절하다는 것을 나타 냈습니다 (app와 dev 모두).

if (is_array($array))주위에이 foreach ($array as $subarray)문제를 해결했다.

죄송합니다. 원인을 설명 할 수는 없지만 해결책을 찾는 데 시간이 걸렸으므로 이것을 관찰로 더 잘 공유 할 것으로 생각했습니다.


0

foreach 루프에 배열을 전달할 때는 is_array 함수를 사용하십시오.

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

0

비어있는 경우 빈 배열을 폴백으로 정의하는 get_value()것은 어떻습니까?
가장 짧은 방법은 생각할 수 없습니다.

$values = get_values() ?: [];

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

0

나는의 조합을 사용합니다 empty, issetis_array

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

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

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

3
-1, $yourArray = 1;반복하려고하면 오류가 발생합니다. empty()적합한 테스트가 아닙니다.
Brad Koch

@BradKoch는 절대적으로 맞습니다. is_array ()는 $ yourArray가 배열인지 테스트하는 유일한 방법입니다. is_array ()가 충분하지 않은 이유에 대한 자세한 내용은 다른 답변을 참조하십시오. 각 반복자도 처리 할 수 ​​있습니다.
cgeisel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.