PHP 개발을 하다 보면 정말 자주 마주치는 에러가 있다. 바로 Warning: Undefined array key 메시지다. 특히 PHP 8.0 이상에서는 이전의 'Undefined index' 에러가 더 엄격하게 변했는데, 대부분의 개발자들은 이 에러가 정확히 뭔지, 왜 나타나는지, 어떻게 막아야 하는지 제대로 이해 못한 채 @(suppress) 연산자를 붙이거나 무작정 isset()을 감싸곤 한다.
이번에는 이 에러의 정확한 원인이 뭔지, 언제 생기는지, 그리고 실무에서 바로 적용할 수 있는 여러 가지 해결 방법을 완벽하게 정리해서 소개하겠다.
이 에러는 배열에 존재하지 않는 키(key)에 접근하려고 할 때 발생한다. PHP 7.x 시대에는 'Undefined index'라는 경고(Warning)였지만, PHP 8.0부터는 더 명확하게 'Undefined array key'로 표기되며, 설정에 따라 Notice나 Warning으로 처리된다.
핵심은 이거다: 배열의 키가 존재하는지 먼저 확인하지 않고 접근하면 이 에러가 난다.
예를 들어, 폼 데이터나 외부 API 응답, 데이터베이스 쿼리 결과처럼 예측 불가능한 데이터를 다룰 때 특히 자주 나타난다. 사용자가 특정 필드를 입력하지 않았거나, API 응답 구조가 바뀌었거나, 데이터베이스에 컬럼이 없을 수 있기 때문이다.
✗ 잘못된 코드 (에러 발생)
<?php
$data = ['name' => 'John', 'email' => 'john@example.com'];
echo $data['phone']; // Warning: Undefined array key "phone"
?>
✓ 올바른 코드
<?php
$data = ['name' => 'John', 'email' => 'john@example.com'];
if (isset($data['phone'])) {
echo $data['phone'];
} else {
echo '전화번호 정보 없음';
}
?>
설명: isset()은 키가 존재하고 NULL이 아닌지 확인한다. 조건부로 접근하면 에러를 완벽하게 막을 수 있다.
✗ 잘못된 경우
<?php
$data = ['name' => 'John', 'phone' => null];
if (isset($data['phone'])) { // isset은 NULL을 감지 못함
echo "전화: " . $data['phone'];
} else {
echo '전화번호 없음'; // 이 부분 출력됨
}
?>
✓ 올바른 코드
<?php
$data = ['name' => 'John', 'phone' => null];
if (array_key_exists('phone', $data)) {
echo "전화: " . ($data['phone'] ?? '정보 없음');
} else {
echo '전화번호 필드 자체가 없음';
}
?>
설명: array_key_exists()는 키의 존재 여부만 확인하므로, 값이 NULL이어도 감지한다. 데이터 구조가 명확할 때 유용하다.
✗ 잘못된 코드
<?php
$_GET = ['search' => ''];
$query = $_GET['keyword']; // Warning: Undefined array key "keyword"
?>
✓ 올바른 코드
<?php
$_GET = ['search' => ''];
$query = $_GET['keyword'] ?? '검색어 없음';
echo $query; // '검색어 없음'
?>
설명: ?? 연산자는 왼쪽 값이 존재하지 않으면 오른쪽 기본값을 반환한다. PHP 7.0 이상에서만 작동하지만, 코드가 깔끔하다.
✓ 올바른 코드
<?php
$config = ['host' => 'localhost'];
$config['port'] ??= 3306; // port가 없으면 3306 할당
$config['user'] ??= 'root'; // user가 없으면 'root' 할당
var_dump($config);
// Array ( [host] => localhost [port] => 3306 [user] => root )
?>
설명: ??= 는 키가 없거나 NULL일 때만 값을 할당한다. 설정값 초기화할 때 매우 유용하다.
✓ 재사용 가능한 서포트 함수
<?php
function array_get($array, $key, $default = null) {
if (is_array($array) && array_key_exists($key, $array)) {
return $array[$key];
}
return $default;
}
// 사용 예제
$user = ['name' => 'Alice', 'email' => 'alice@example.com'];
echo array_get($user, 'name'); // 'Alice'
echo array_get($user, 'phone', 'N/A'); // 'N/A'
echo array_get($user, 'address', '주소 없음'); // '주소 없음'
?>
설명: 복잡한 배열 구조나 여러 곳에서 데이터에 접근할 때, 이 함수를 만들어두면 코드 가독성이 훨씬 좋다.
✗ 잘못된 코드 (여러 에러 발생)
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'];
$email = $_POST['email'];
$phone = $_POST['phone']; // Warning: Undefined array key "phone"
$message = $_POST['message']; // Warning: Undefined array key "message"
// 저장 로직...
}
?>
✓ 올바른 코드 (안전한 처리)
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$phone = $_POST['phone'] ?? ''; // 선택 필드
$message = $_POST['message'] ?? ''; // 선택 필드
// 유효성 검사
if (empty($name) || empty($email)) {
die('필수 필드를 입력하세요.');
}
// 저장 로직...
echo '정보 저장 완료';
}
?>
설명: 사용자 입력 데이터는 예측 불가능하므로 항상 ?? 연산자나 isset()으로 기본값을 지정하고, 필수 필드는 empty()로 검사한다.
| 상황 | ✗ 잘못된 방법 | ✓ 올바른 방법 |
|---|---|---|
| NULL 값 구분 필요 | isset($array['key']) (NULL 값을 감지 못함) |
array_key_exists('key', $array) (키 존재 여부만 확인) |
| 빠른 기본값 설정 | if (isset(...)) { ... } else { ... } | $var = $array['key'] ?? 'default'; |
| 에러 무시 (나쁜 관행) | @$array['key'] (에러만 숨김, 디버깅 어려움) |
array_get($array, 'key') (구조화된 처리) |
| 중첩 배열 접근 | $data['user']['phone'] (중간에 없으면 에러) |
$data['user']['phone'] ?? null (각 단계마다 ?? 처리) |
php.ini에서 에러 리포팅 레벨을 조정할 수 있지만, 근본 해결은 아니다.
<?php
// 임시로 경고 억제 (권장하지 않음)
error_reporting(E_ALL & ~E_WARNING);
// 또는
ini_set('display_errors', 0);
?>
경고: 에러 메시지를 숨기는 것은 버그 추적을 어렵게 만든다. 반드시 코드 자체를 수정하는 것이 정답이다.
Warning: Undefined array key 에러는 배열 접근의 안전성 문제를 지적하는 PHP의 친절한 경고다. 이 에러를 무시하거나 억제하는 대신, 위의 5가지 방법(isset, array_key_exists, ??, ??=, array_get) 중 상황에 맞는 것을 선택해 처리하면 된다.
특히 사용자 입력, 외부 API 응답, 데이터베이스 결과처럼 구조를 신뢰할 수 없는 데이터를 다룰 때는 항상 배열 키 존재 여부를 먼저 확인하는 습관을 들이자. 이런 작은 방어 코딩이 모여서 버그 없는 안정적인 서버를 만드는 것이다. 이 글의 '서포트 함수 array_get()' 부분을 참고해 프로젝트에 추가하면, 향후 배열 접근 에러로 고민할 일이 훨씬 줄어들 것이다.