디버깅과 에러 처리
버그, 디버그, 에러
버그(Bug) 는 프로그램의 오류를 뜻합니다.
1940년대 초기 컴퓨터에서 실제로 나방 한 마리가 회로에 끼어 오작동을 일으킨 사건에서 유래했습니다.
그 이후로 프로그램 오류를 버그라고 부르게 됐습니다.
디버그(Debug) 는 버그를 찾아 수정하는 과정입니다. de- 는 "제거한다"는 뜻입니다.
에러(Error) 는 프로그램이 기대한 대로 동작하지 않는 현상입니다.
버그 외에도 사용자 실수, 환경 문제 등으로도 발생합니다.
에러의 종류
1. 문법 에러 (Syntax Error)
가장 흔하고, 가장 빨리 잡을 수 있는 에러입니다.
PHP가 코드를 파싱하는 단계에서 바로 잡아냅니다.
세미콜론 빠뜨리기
<?php
echo "첫 번째 문장" // 세미콜론이 없어요!
echo "두 번째 문장";
// Parse error: syntax error, unexpected token "echo"
중괄호 안 닫기
<?php
if ($name === '홍길동') {
echo "안녕하세요, 홍길동님!";
// 닫는 } 가 없습니다
// Parse error: syntax error, unexpected end of file
따옴표 안 닫기
<?php
echo "따옴표가 안 닫혔어요;
$sum = $a + $b;
// Parse error: syntax error, unexpected variable "$sum"
VSCode나 PhpStorm 같은 편집기를 쓰면 문법 강조(Syntax Highlight) 기능이 있어서
따옴표가 안 닫힌 부분의 색이 다르게 표시됩니다. 색이 이상하면 의심해보세요.
2. 실행 시간 에러 (Runtime Error)
문법은 맞지만 실행하다가 문제가 생기는 에러입니다.
<?php
$a = 5;
$b = $a - 5; // $b = 0
$c = $a / $b; // 0으로 나누기!
// Warning: Division by zero
$a가 외부에서 넘어오는 값이라면, 상황에 따라 에러가 날 수도 안 날 수도 있습니다.
이런 경우엔 미리 검사해야 합니다.
<?php
$a = 5;
$b = $a - 5;
if ($b === 0) {
echo '나눌 수 없습니다.';
} else {
echo $a / $b;
}
3. 논리 에러 (Logic Error)
가장 무서운 에러입니다.
에러 메시지가 전혀 없는데 결과가 이상합니다.
컴퓨터는 문법상 틀린 게 없으니 그냥 실행하는 거고, 뭐가 잘못됐는지는 개발자만 압니다.
대입(=)과 비교(==, ===) 혼동
<?php
$name = '홍길동';
if ($name = '김철수') { // ==가 아니라 =입니다!
echo $name; // 김철수 — 의도와 다른 결과
}
$name = '김철수'는 비교가 아니라 대입입니다.
$name에 '김철수'를 넣은 뒤, 그 값이 비어 있지 않으므로 true가 됩니다.
항상 === (일치 비교) 또는 == (동등 비교)를 써야 합니다.
경계값 실수
<?php
// 1부터 10까지 더하려고 했는데...
$sum = 0;
for ($i = 1; $i < 10; $i++) { // $i <= 10 이어야 합니다!
$sum += $i;
}
echo $sum; // 45 — 1+2+...+9, 10이 빠졌습니다
논리 에러는 결과를 직접 계산해보거나, var_dump()로 중간값을 찍어보면서 추적합니다.
PHP 에러 레벨
PHP에는 에러 심각도에 따라 레벨이 있습니다.
| 레벨 | 설명 |
|---|---|
E_ERROR | 치명적 에러. 실행이 중단됩니다 |
E_WARNING | 경고. 실행은 계속되지만 문제가 있습니다 |
E_NOTICE | 알림. 잠재적 문제를 알려줍니다 |
E_DEPRECATED | 더 이상 권장하지 않는 기능을 쓰고 있습니다 |
개발 중에는 모든 에러를 표시하고, 운영 서버에서는 로그에만 기록하는 게 좋습니다.
<?php
// 개발 환경 — php.ini 또는 코드에서 설정
ini_set('display_errors', '1');
error_reporting(E_ALL);
// 운영 환경
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php_errors.log');
운영 서버에서 에러 메시지가 화면에 그대로 나오면 DB 구조, 파일 경로 같은 민감한 정보가
사용자에게 노출될 수 있습니다. 반드시display_errors를 꺼두세요.
예외 처리 (try / catch)
PHP 5부터 예외(Exception) 처리가 지원되고, 현대 PHP에서는 에러 처리의 기본이 됐습니다.
<?php
declare(strict_types=1);
function divide(int $a, int $b): float {
if ($b === 0) {
throw new InvalidArgumentException('0으로 나눌 수 없습니다.');
}
return $a / $b;
}
try {
echo divide(10, 2); // 5
echo divide(10, 0); // 예외 발생!
} catch (InvalidArgumentException $e) {
echo '에러: ' . $e->getMessage();
} finally {
echo '항상 실행됩니다.'; // 예외 여부와 관계없이 실행
}
finally 블록은 예외 발생 여부와 관계없이 항상 실행됩니다.
DB 연결 닫기, 파일 닫기 같이 "반드시 해야 하는 정리 작업"을 여기에 씁니다.
여러 예외 처리
<?php
try {
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'id', 'pw');
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$userId]);
} catch (PDOException $e) {
error_log('DB 에러: ' . $e->getMessage());
echo 'DB 오류가 발생했습니다.';
} catch (Exception $e) {
error_log('일반 에러: ' . $e->getMessage());
echo '오류가 발생했습니다.';
}
디버깅 도구
var_dump() — 타입과 값 확인
<?php
$data = ['name' => '홍길동', 'age' => 30, 'active' => true];
var_dump($data);
/*
array(3) {
["name"] => string(9) "홍길동"
["age"] => int(30)
["active"] => bool(true)
}
*/
echo와 달리 타입 정보까지 함께 보여줍니다. 디버깅할 때 가장 많이 씁니다.
print_r() — 배열/객체를 읽기 좋게
<?php
$users = [
['name' => '홍길동', 'age' => 30],
['name' => '김철수', 'age' => 25],
];
print_r($users);
/*
Array
(
[0] => Array
(
[name] => 홍길동
[age] => 30
)
[1] => Array
(
[name] => 김철수
[age] => 25
)
)
*/
error_log() — 로그 파일에 기록
운영 서버에서는 화면에 디버그 정보를 뿌리면 안 됩니다.
error_log()로 로그 파일에 조용히 기록해두세요.
<?php
error_log('사용자 ID: ' . $userId . ', 액션: 로그인 시도');
error_log(print_r($requestData, true)); // 배열도 문자열로 변환해서 기록
버그는 부끄러운 게 아닙니다. 모든 프로그래머가 매일 마주칩니다.
에러 메시지를 무서워하지 마세요. 에러 메시지는 "여기가 문제야"라고 친절하게 알려주는 것입니다.
메시지를 읽고, 해당 줄을 확인하고,var_dump()로 값을 추적하는 게 디버깅의 기본입니다.