foreach ($array as $value)는 모든 요소마다 블록을 한 번씩 실행하며, $value에 현재 요소가 들어갑니다. 키도 얻으려면 foreach ($array as $key => $value)로 쓰세요.
foreach는 키가 무엇이든 모든 배열에서 동작하고, 카운터를 관리하거나 길이를 확인할 필요가 없습니다. PHP에서 가장 자주 쓰게 될 반복문입니다.
키와 값 순회하기
$key => $value에서 이름은 자유롭게 정할 수 있습니다: $name => $age, $id => $user, $k => $v. 리스트에서 키는 위치 0, 1, 2입니다. 연관 배열에서는 직접 정의한 문자열 키입니다.
마지막 반복문은 많은 사람이 놀라는 세부 사항을 보여 줍니다. "1"처럼 정수처럼 보이는 문자열 키는 정수 1로 저장됩니다. "01"은 정규 정수 형태가 아니므로 문자열로 남습니다.
foreach에서 인덱스 얻기
리스트에서는 키가 인덱스이므로 foreach ($items as $i => $item)만으로 충분합니다. 연관 배열에는 숫자 위치가 없으므로 카운터를 두세요. 첫 번째나 마지막 요소를 다르게 처리하려면 키를 array_key_first()나 array_key_last()와 비교하세요.
마지막 반복문은 이름 사이에 쉼표를 넣지만 마지막 이름 뒤에는 넣지 않습니다. 딱 이 작업이라면 implode(', ', array_keys($scores))가 더 짧습니다. array_key_last() 확인은 마지막 회차에 구분자만이 아니라 다른 로직이 필요할 때 쓰는 것입니다.
foreach에서 배열 값 바꾸기(참조)
$value는 복사본입니다. 여기에 대입해도 배열은 바뀌지 않습니다. 배열을 바꾸려면 &$value로 참조 반복을 하거나 키를 통해 다시 쓰세요.
둘 다 동작합니다. 키를 쓰는 방식은 반복문이 끝난 뒤 숨은 상태가 남지 않아서 많은 팀이 선호합니다. 기존 배열을 바꾸는 대신 새 배열을 만들 때는 array_map()도 선택지입니다.
관련된 질문: 반복하는 도중에 요소를 추가하면 어떻게 될까요? 일반 foreach는 반복이 시작될 때의 배열을 순회하므로, 안에서 $prices[] = ...를 해도 회차가 늘어나지 않습니다. 참조 반복문은 살아 있는 배열을 순회하므로 새 요소도 방문합니다.
foreach 참조 반복의 unset() 함정
foreach ($arr as &$v) 뒤에도 변수 $v는 여전히 배열의 마지막 요소를 참조합니다. 나중에 일반 반복문에서 $v라는 이름을 다시 쓰면 매 회차가 그 마지막 요소에 값을 씁니다. 실행하고 마지막 항목을 보세요.
두 번째 반복문은 $letters[2]에 A, 그다음 B, 그다음 마지막 요소 자신의 값을 대입하는데, 마지막 회차에서는 그 칸에 이미 B가 들어 있습니다. 해결은 한 줄입니다. 모든 참조 foreach 바로 뒤에 unset($v);를 넣으세요.
foreach에서 break와 continue
break는 반복문을 빠져나가고 continue는 다음 요소로 건너뜁니다. 흔한 패턴은 검색입니다. 필요한 것을 찾을 때까지 반복하다가 break해서 배열의 나머지를 확인하지 않습니다.
중첩 반복문에서 break 2는 안쪽 반복문과 그것을 감싼 반복문을 빠져나가고, continue 2는 바깥 반복문의 다음 회차로 넘어갑니다.
중첩 배열과 list()를 쓰는 foreach
데이터의 행은 배열 안의 배열입니다. 행을 순회한 다음 각 행을 순회하거나, 배열 구조 분해로 foreach 줄에서 필드를 바로 꺼내세요. 리스트에는 [$a, $b], 연관 행에는 ['key' => $var]를 씁니다. list($a, $b)는 [$a, $b]의 옛 표기입니다.
건너뛴 요소와 중첩 패턴을 포함한 [...] = 문법은 구조 분해 페이지에서 더 자세히 다룹니다.
foreach로 HTML 목록이나 표 만들기
템플릿에서는 foreach (...):와 endforeach;의 콜론 형태가 태그 사이에서 반복문을 읽기 쉽게 해 줍니다. 이 블록은 표를 만들고, 열 제목은 링크입니다. Page 탭에서 하나를 클릭하면 $_GET['sort']가 설정된 채로 같은 스크립트가 다시 실행되어 행이 새 순서로 나옵니다.
이 블록에서 따라 할 만한 습관이 두 가지 있습니다. URL의 sort 값은 사용 전에 허용된 열 목록과 대조해 확인하고, 사용자 텍스트가 들어 있을 수 있는 값은 HTML에 출력할 때 모두 htmlspecialchars()를 거칩니다.
null, 빈 배열, 객체에 대한 foreach
빈 배열은 괜찮습니다. 본문이 실행되지 않을 뿐입니다. null, 문자열, 숫자는 안 됩니다. PHP가 경고를 출력하고 반복문을 건너뜁니다. $tags = null; foreach ($tags as $tag)의 경우 다음이 출력됩니다.
Warning: foreach() argument must be of type array|object, null given in /var/www/html/index.php on line 4
디코딩한 JSON의 선택적 필드처럼 가끔 비어 있는 데이터에서 가장 자주 생깁니다. ??로 빈 배열을 대신 쓰세요.
foreach ($data['tags'] ?? [] as $tag) {
echo $tag;
}
메시지에 나오는 object는 실제로 가능합니다. 객체에 대한 foreach는 반복문이 실행되는 위치에서 보이는 속성(클래스 밖이라면 public 속성)을 방문하며, 속성 이름이 키가 됩니다. Iterator나 IteratorAggregate를 구현한 클래스와 제너레이터는 foreach가 무엇을 볼지 스스로 정합니다.
foreach, for, array_map 비교
| 사용 | 언제 |
|---|---|
foreach | 모든 요소가 필요할 때(키는 있어도 없어도 됨). 리스트든 연관 배열이든 어떤 배열에서나 동작합니다. |
for | 셀 때(1부터 100까지, 두 번째 요소마다) 또는 인덱스로 이웃 요소가 필요할 때($a[$i - 1]). for 반복문을 참고하세요. |
array_map() | 각 요소를 변환해 새 배열을 만들 때. 흔히 fn으로 한 줄에 씁니다. |
array_filter() | 조건을 통과한 요소만 남길 때. |
빠르게 고르는 방법: 반복문 본문이 요소마다 새 값을 계산하기만 한다면 array_map(fn($x) => $x * 2, $a)가 그것을 한 줄로 말해 줍니다. 부수 효과(출력, 저장, 여러 가지를 동시에 세기)가 있거나 break가 필요하면 foreach를 쓰세요.
자주 묻는 질문
PHP foreach에서 키와 값을 얻으려면 어떻게 하나요?
=> 형태를 쓰세요: foreach ($array as $key => $value) { echo "$key: $value"; }. 일반 리스트에서 키는 인덱스(0, 1, 2)이고, 연관 배열에서는 'name' 같은 문자열 키입니다.
PHP foreach에서 인덱스를 얻으려면 어떻게 하나요?
리스트라면 키가 이미 인덱스입니다: foreach ($items as $i => $item). 연관 배열이라면 직접 카운터를 두세요. 반복문 전에 $i = 0;, 각 회차 끝에 $i++를 씁니다. array_key_first()와 array_key_last()는 어떤 키가 처음이고 마지막인지 알려 줍니다.
PHP foreach 안에서 배열 값을 바꾸려면 어떻게 하나요?
&로 참조 반복을 하세요: foreach ($prices as &$price) { $price *= 2; } unset($price);. 또는 키를 통해 쓰세요: foreach ($prices as $key => $price) { $prices[$key] = $price * 2; }. 단순한 $price = ...는 복사본만 바꿉니다.
PHP foreach 참조 반복 후 마지막 요소가 중복되는 이유는 무엇인가요?
foreach ($arr as &$v) 뒤에도 $v는 여전히 마지막 요소를 참조합니다. 이어서 foreach ($arr as $v)를 실행하면 각 값을 그 마지막 칸에 쓰게 되어, 결국 끝에서 두 번째 값이 반복됩니다. 참조 반복문 바로 뒤에 unset($v);를 호출하세요.
PHP에서 foreach를 빠져나오려면 어떻게 하나요?
break;는 반복문을 즉시 멈추고 continue;는 다음 요소로 건너뜁니다. 중첩 반복문에서 break 2;는 안쪽과 바깥쪽 반복문을 모두 빠져나옵니다.