PHP 개발하다 보면 정말 자주 마주치는 경고 메시지가 있다. 바로 "Warning: Undefined variable"이다. 콘솔에 떠도 무시하고 지나가는 개발자들이 많지만, 실제로는 버그의 신호다. 다만 대부분의 개발자들은 이 경고가 정확히 뭘 의미하고, 왜 발생하며, 어떻게 근본적으로 해결해야 하는지 모른 채 인터넷에서 가져온 코드를 그냥 복사해 붙인다. 이번에는 이 경고가 정확히 뭔지, 왜 필요한지, 어떻게 완벽하게 예방하는지 실전 기반으로 정리해서 소개하겠다.
먼저 상황을 상상해보자. PHP 코드를 실행했을 때 "Notice: Undefined variable: username in /path/to/file.php on line 5" 같은 메시지가 뜬다. 이건 어떤 의미일까?
간단하다. 변수를 선언하지 않은 채로 사용하려고 했다는 뜻이다. PHP는 동적 타입 언어라서 변수를 미리 선언할 필요가 없지만, 그렇다고 선언 없이 아무 변수나 막 쓸 수는 없다는 뜻이다.
왜 이런 에러가 나올까? 주로 이런 경우들이다:
- 변수 이름을 잘못 입력했다 (예: $usernme vs $username)
- 조건문이나 반복문 내에서만 변수를 선언했다
- 폼 데이터나 GET/POST 파라미터를 isset() 체크 없이 사용했다
- 함수 밖에서 함수 내부 변수를 참조하려고 했다
가장 흔한 상황이 폼에서 넘어온 데이터를 처리할 때다.
✗ 잘못된 코드
<?php
// form.html 에서 POST로 username을 보냈다고 하자
echo "사용자명: " . $_POST['username'];
// 만약 username이 없으면 "Notice: Undefined index: username" 경고 발생
?>
✓ 올바른 코드 (isset 체크)
<?php
if (isset($_POST['username'])) {
echo "사용자명: " . $_POST['username'];
} else {
echo "사용자명이 입력되지 않았습니다.";
}
?>
✓ 더 나은 방법 (null coalescing 연산자)
<?php
// PHP 7.0 이상에서 사용 가능
echo "사용자명: " . ($_POST['username'] ?? "미입력");
?>
✓ 가장 안전한 방법 (null safe operator + 기본값)
<?php
// PHP 8.0 이상에서 사용 가능
$username = $_POST['username'] ?? '';
echo "사용자명: " . htmlspecialchars($username);
?>
✗ 잘못된 코드
<?php
$age = 25;
if ($age > 18) {
$status = "성인";
}
// if 블록 바깥에서 접근하면 경고 발생
echo "상태: " . $status; // Notice: Undefined variable: status
?>
✓ 올바른 코드 (변수를 먼저 초기화)
<?php
$age = 25;
$status = ""; // 사전 선언
if ($age > 18) {
$status = "성인";
} else {
$status = "미성년자";
}
echo "상태: " . $status; // OK
?>
✗ 잘못된 코드
<?php
$user = ['name' => 'John'];
// 'email' 키가 없으면 경고 발생
echo $user['email']; // Notice: Undefined array key: email
?>
✓ 올바른 코드
<?php
$user = ['name' => 'John'];
if (array_key_exists('email', $user)) {
echo $user['email'];
} else {
echo "이메일 정보 없음";
}
// 또는 더 간단하게
echo $user['email'] ?? "이메일 정보 없음";
?>
실제 프로젝트에서 자주 사용하는 사용자 가입 폼을 안전하게 처리하는 방법을 보자.
<?php
// 기본값 설정
$username = '';
$email = '';
$password = '';
$error = '';
// POST 요청일 때만 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 변수 할당 (isset 체크 + trim)
$username = isset($_POST['username']) ? trim($_POST['username']) : '';
$email = isset($_POST['email']) ? trim($_POST['email']) : '';
$password = isset($_POST['password']) ? trim($_POST['password']) : '';
// 유효성 검증
if (empty($username)) {
$error = "사용자명을 입력하세요.";
} elseif (empty($email)) {
$error = "이메일을 입력하세요.";
} elseif (empty($password)) {
$error = "비밀번호를 입력하세요.";
} else {
// 데이터 처리 (DB 저장 등)
echo "회원가입 완료!";
exit();
}
}
?>
<!-- HTML 폼 -->
<form method="POST">
<?php if ($error): ?>
<p style="color: red;"><?php echo htmlspecialchars($error); ?></p>
<?php endif; ?>
<input type="text" name="username" value="<?php echo htmlspecialchars($username); ?>" required>
<input type="email" name="email" value="<?php echo htmlspecialchars($email); ?>" required>
<input type="password" name="password" required>
<button type="submit">가입</button>
</form>
| 실수 | 설명 | 해결책 |
|---|---|---|
| 에러 무시하기 | @ 연산자로 경고를 무시하는 것 (예: @$_POST['name']) | 근본 원인을 해결하고, isset/null coalescing 사용 |
| 변수 존재 여부만 체크 | isset만 사용하면 빈 문자열도 통과 | empty()나 string validation 함께 사용 |
| 전역 변수 오염 | 함수 내에서 전역 변수를 그냥 사용 | 매개변수로 전달하거나 global 키워드 명시 |
| 타입 힌트 무시 | PHP 7+의 타입 선언을 사용하지 않음 | 함수 선언 시 타입 힌트 명시 (예: function getName(string $name): string) |
php.ini 파일에서 에러 리포팅 수준을 높여두면 개발 중에 이런 실수를 더 빨리 발견할 수 있다.
; php.ini 설정
error_reporting = E_ALL
display_errors = 1
; 또는 PHP 코드에서 직접 설정
error_reporting(E_ALL);
ini_set('display_errors', 1);
"Undefined variable" 경고는 결국 변수를 사용하기 전에 제대로 초기화했는가의 문제다. 작은 체크 하나가 모여서 견고한 코드를 만든다는 점을 잊지 말자. 이 글의 "변수 초기화 원칙"과 "isset/null coalescing 활용법"을 참고해 지금 당신의 프로젝트 코드를 한 번 스캔해보면, 예상 밖의 버그를 여럿 발견할 수 있을 것이다.