PHP 코드를 작성하다 보면 갑자기 화면에 노란 경고창이 뜨면서 "Warning: Undefined variable"이라는 메시지를 본 적 있을까. 대부분의 개발자는 이걸 무시하거나 error_reporting을 낮춰서 경고를 숨겨버리는 방식으로 대충 넘어간다. 다만 이런 습관이 쌓이면 프로덕션 환경에서 예기치 않은 버그를 일으키거나 보안 취약점으로 이어진다. 이번에는 정확히 어떤 상황에서 이 에러가 발생하는지, 왜 무시하면 안 되는지, 그리고 어떻게 올바르게 처리하는지 완벽하게 정리해서 소개하겠다.

 

1단계. Undefined variable 에러 이해하기

PHP는 변수를 처음 사용할 때 자동으로 생성하는 언어다. 즉, 변수를 선언하는 별도의 과정 없이 바로 값을 할당하면 된다. 하지만 이것이 역설적으로 가장 흔한 버그의 원인이 된다. 변수 이름을 잘못 쓰거나 아직 할당되지 않은 변수를 참조하면 PHP는 E_WARNING 수준의 경고를 발생시킨다. 이 경고를 무시하면 변수는 NULL 값을 갖게 되고, 이후 논리 오류로 이어진다.

 

Undefined variable의 일반적인 패턴

가장 흔한 경우는 변수 이름을 오타로 쓸 때다. 예를 들어 $user_name을 $username으로 잘못 쓰거나, 조건문 분기에서만 변수를 정의한 후 외부에서 참조하는 경우다. 또 다른 케이스는 배열 키가 존재하지 않을 때인데, PHP는 배열 요소도 변수처럼 다루므로 같은 경고가 나타난다.

 

2단계. Undefined variable 발생 원인 5가지

 

1) 타이핑 오류

변수 이름을 잘못 썼을 때 발생한다. 이는 자동 완성이나 코드 검증 도구로 쉽게 잡을 수 있지만, 동적 기능이 많은 PHP 코드에서는 놓치기 쉽다.

 

2) 조건부 선언

변수가 특정 조건에서만 정의된 후, 그 조건 밖에서 참조될 때다. 예를 들어 if 블록 안에서만 $result를 정의했는데, 이후 코드에서 항상 $result를 사용하면 조건이 거짓일 때 경고가 난다.

 

3) 배열 키 미존재

$_GET['page']처럼 외부 입력에 의존하는 배열 요소에 접근할 때, 해당 키가 존재하지 않으면 경고가 발생한다.

 

4) 범위(Scope) 오류

함수나 클래스 메서드 내부에서 전역 변수에 접근할 때, global 키워드를 빠뜨렸을 때다.

 

5) 기본값 미설정

반복문이나 배열 처리 후 변수를 누적하는데, 루프 이전에 초기화하지 않았을 때 발생한다.

 

3단계. 실전 코드 예제

 

예제 1: 배열 키 미존재로 인한 경고

✗ 잘못된 코드 (경고 발생)

<?php
$user = array('name' => 'John');
echo $user['age'];  // Notice: Undefined array key "age"
?>

위 코드는 배열에 'age' 키가 없어서 경고를 발생시킨다. 이 변수는 NULL이 되고, echo는 아무것도 출력하지 않는다.

✓ 올바른 코드 1: isset() 검사

<?php
$user = array('name' => 'John');
echo isset($user['age']) ? $user['age'] : 'Unknown';
// 결과: Unknown
?>

isset()은 변수가 존재하고 NULL이 아닌지 확인한다. 배열 키 검사의 표준 방법이다.

✓ 올바른 코드 2: null 병합 연산자 (PHP 7.0+)

<?php
$user = array('name' => 'John');
echo $user['age'] ?? 'Unknown';
// 결과: Unknown
?>

null 병합 연산자 ??는 isset() 체크 + 기본값 설정을 한 줄에 처리한다. 더 간결하고 읽기 좋다.

 

예제 2: 조건부 변수 선언

✗ 잘못된 코드

<?php
if ($status === 'active') {
    $message = 'User is active';
}
echo $message;  // Warning: Undefined variable $message (if $status != 'active')
?>

$message가 if 블록 안에서만 정의되므로, 조건이 거짓이면 경고가 발생한다.

✓ 올바른 코드

<?php
$message = '';  // 미리 초기화
if ($status === 'active') {
    $message = 'User is active';
}
echo $message;  // 결과: (빈 문자열 또는 'User is active')
?>

변수를 함수나 조건문 이전에 선언해서 초기화하는 것이 기본이다.

 

예제 3: $_GET 같은 슈퍼글로벌 변수 안전한 접근

✗ 잘못된 코드

<?php
$page = $_GET['page'];  // Warning: Undefined array key "page"
echo 'Page: ' . $page;
?>

사용자가 page 파라미터를 보내지 않으면 경고가 발생한다.

✓ 올바른 코드

<?php
$page = $_GET['page'] ?? 1;
echo 'Page: ' . $page;  // 결과: Page: 1 (기본값)
?>

null 병합 연산자로 기본값을 설정하는 것이 일반적이다. 더 복잡한 검증이 필요하면 필터 함수를 사용한다.

 

예제 4: 반복문에서 변수 누적

✗ 잘못된 코드

<?php
$numbers = [1, 2, 3, 4, 5];
foreach ($numbers as $num) {
    $sum += $num;  // Warning: Undefined variable $sum
}
echo $sum;  // 결과: null (연산 안 됨)
?>

$sum이 초기화되지 않아 += 연산이 경고를 발생시킨다.

✓ 올바른 코드

<?php
$numbers = [1, 2, 3, 4, 5];
$sum = 0;  // 초기화
foreach ($numbers as $num) {
    $sum += $num;
}
echo $sum;  // 결과: 15
?>

누적 작업을 할 변수는 루프 이전에 반드시 초기화해야 한다.

 

예제 5: 전역 변수 scope 오류

✗ 잘못된 코드

<?php
$config = ['db' => 'localhost'];

function get_config() {
    echo $config['db'];  // Warning: Undefined variable $config
}

get_config();
?>

함수 내부에서 전역 변수에 접근할 수 없다.

✓ 올바른 코드

<?php
$config = ['db' => 'localhost'];

function get_config() {
    global $config;  // 전역 변수 명시
    echo $config['db'];  // 결과: localhost
}

get_config();
?>

함수 내부에서 전역 변수를 사용하려면 global 키워드를 명시해야 한다. 더 나은 방식은 변수를 함수 인자로 전달하는 것이다.

 

4단계. 주의사항과 흔한 실수

 

실수 1: error_reporting을 무시로 설정

✗ 나쁜 방법

<?php
error_reporting(0);  // 모든 에러 무시
$message = $undefined_var;  // 경고가 나타나지 않지만 여전히 NULL
?>

경고를 무시해도 논리 오류는 여전히 존재한다. 프로덕션에서 예기치 않은 버그를 일으킨다.

✓ 올바른 방법

<?php
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);  // 필요한 에러만 활성화
// 또는 php.ini에서 관리
?>

개발 환경에서는 모든 경고를 표시하고, 코드를 수정해서 경고를 제거하는 것이 기본이다.

 

실수 2: 빈 문자열과 NULL 구분 안 함

✗ 잘못된 코드

<?php
$user = array('name' => '');
if ($user['name']) {  // false (빈 문자열)
    echo 'Name exists';
}
if (isset($user['name'])) {  // true (키는 존재)
    echo 'Key exists';
}
?>

isset()은 키 존재 여부를 확인하고, 단순 조건 검사는 값의 진위를 판단한다. 용도를 구분해야 한다.

 

실수 3: 배열 키에 함수 호출 결과 직접 사용
<?php
$data = ['user_id' => 123];
$key = get_key_name();  // "user_id" 반환
echo $data[$key] ?? 'Not found';  // 결과: 123
?>

동적 키를 사용할 때도 항상 ?? 연산자로 기본값을 설정하자.

 

5단계. 정리 및 다음 단계

Undefined variable 경고는 단순한 알림이 아니라 논리 오류의 신호다. isset()이나 null 병합 연산자로 변수 존재 여부를 확인하고, 배열 키 접근 시 기본값을 설정하는 습관이 모여서 버그 없는 견고한 코드를 만든다. 특히 외부 입력(GET, POST, 세션 등)을 다룰 때는 더욱 조심해야 한다. 이 글의 5가지 예제를 참고해서 자신의 코드를 다시 검토하면, 숨어 있던 잠재적 버그를 많이 찾아낼 수 있을 것이다.