본문 바로가기

비개발자의 개발 일지

현장 팀장에서 수출 ERP까지 — AI와 함께 시스템을 만든 기록

시리즈 보기
php

PHP PDO 예외처리 완전 정리 — try/catch, setAttribute, PDOException 완전 해설

by 왕진 2026. 7. 13.
반응형

 

 

Web Development · PHP + MySQL

PHP PDO 예외처리 완전 정리

try/catch, setAttribute(ERRMODE_EXCEPTION), PDOException, getMessage() 완전 해설
시작 오늘 분석할 코드

일부러 틀린 DB 사용자명(samplee)으로 접속을 시도해 에러 처리 흐름을 확인한다. try/catchPDOException, setAttribute로 PDO 에러를 제대로 처리하는 방법을 배운다.

try { $pdo = new PDO( 'mysql:host=localhost;dbname=sampledb;charset=utf8', 'samplee', // ← 의도적 오타 (sample이 아님) 'password' ); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); print "접속하였습니다."; } catch(PDOException $Exception) { die('접속 오류:' . $Exception->getMessage()); }
실제 출력 미리보기 (samplee로 접속 실패 시)
접속 오류:SQLSTATE[HY000] [1045] Access denied for user 'samplee'@'localhost'
→ PDOException 발생 → catch 블록 실행 → getMessage()가 에러 내용 반환 → die()로 출력 후 종료
접속하였습니다. (성공 시 — try 블록 끝까지 실행)
용어 핵심 용어 정리
try/catchtry 블록에서 예외 발생 시 catch로 점프. PHP 예외처리의 기본 구조
PDOExceptionPDO 에러 시 발생하는 예외 클래스. catch에서 객체로 받아 getMessage()로 내용 조회
getAttributePDO 속성 값을 읽는 메서드 (반대: setAttribute로 설정)
ATTR_ERRMODEPDO 에러 처리 방식 설정. ERRMODE_EXCEPTION으로 설정하면 에러 시 예외 발생
ERRMODE_EXCEPTIONPDO 에러를 PDOException으로 던지는 모드. try/catch로 잡아서 처리 가능
ATTR_EMULATE_PREPARES준비된 구문(prepared statement)을 PHP에서 에뮬레이션할지 여부. false=MySQL이 직접 처리
getMessage()예외 객체의 메서드. 발생한 에러의 메시지 문자열을 반환
die()메시지를 출력하고 스크립트를 즉시 종료. catch에서 복구 불가능한 에러 처리에 사용

1 try/catch 구조 — 예외처리의 흐름
에러 발생 시 catch로 제어가 이동한다

try 블록 안에서 예외(Exception)가 발생하면, 그 시점에서 실행이 중단되고 즉시 catch 블록으로 제어가 이동한다. try 블록의 나머지 코드는 실행되지 않는다. catch에서는 예외 객체를 받아 에러 내용을 처리한다.

1
new PDO() 실행'samplee' 계정으로 접속 시도
2
PDOException 발생잘못된 계정 → Access Denied → 예외 throw
3
catch 블록으로 이동PDOException 객체가 $Exception에 저장됨
4
getMessage() 호출에러 메시지 문자열 반환
5
die() 실행에러 메시지 출력 후 스크립트 종료
try { new PDO() }
PDOException 발생
catch($Exception)
die(getMessage())

2 setAttribute — PDO 동작 방식 설정
ATTR_ERRMODE와 ATTR_EMULATE_PREPARES 두 가지 설정

PDO는 기본적으로 에러를 조용히 무시한다(ERRMODE_SILENT). setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)을 설정해야 에러 시 예외를 던지고 try/catch로 잡을 수 있다. 이 설정이 없으면 쿼리 에러가 발생해도 코드가 계속 실행된다.

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 에러 발생 시 PDOException throw → try/catch로 처리 가능 $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // prepared statement를 PHP가 에뮬레이션하지 않고 MySQL이 직접 처리 // 더 정확한 타입 처리 + 실제 SQL Injection 방어
상수 의미
ATTR_ERRMODE ERRMODE_SILENT (기본) 에러를 조용히 무시. 권장하지 않음
ATTR_ERRMODE ERRMODE_WARNING PHP Warning 발생. 실행은 계속됨
ATTR_ERRMODE ERRMODE_EXCEPTION PDOException throw. try/catch로 처리. 권장
ATTR_EMULATE_PREPARES true (기본) PHP가 prepared statement를 시뮬레이션
ATTR_EMULATE_PREPARES false MySQL이 직접 처리. 더 안전하고 정확

3 PDOException과 getMessage()
예외 객체에서 에러 정보를 꺼내는 방법

catch(PDOException $Exception)에서 $Exception은 PDOException 클래스의 객체다. 이 객체는 에러 정보를 담고 있으며, getMessage()는 에러 메시지 문자열을 반환한다. mysqli의 connect_errorconnect_errno가 하는 역할을 이 객체 하나가 담당한다.

catch(PDOException $Exception) { // $Exception은 PDOException 객체 $Exception->getMessage(); // 에러 메시지 문자열 반환 $Exception->getCode(); // SQLSTATE 에러 코드 반환 $Exception->getFile(); // 에러 발생 파일명 $Exception->getLine(); // 에러 발생 줄 번호 } // mysqli와 비교 // die('Connect Error:('.$mysqli->connect_errno.') '.$mysqli->connect_error); // die('접속 오류:' . $Exception->getMessage()); ← PDO 방식

 

반응형

 

4 PDOException 메서드 목록
catch에서 꺼낼 수 있는 에러 정보들

PDOException은 PHP의 RuntimeException을 상속하므로 일반 예외 메서드를 모두 사용할 수 있다. 에러의 종류와 위치를 정확히 파악하는 데 유용하다.

메서드 반환값 예시
getMessage() 에러 메시지 문자열 SQLSTATE[HY000] [1045] Access denied...
getCode() SQLSTATE 에러 코드 HY000, 23000 등
getFile() 에러 발생 파일명 C:\xampp\htdocs\dbtest4.php
getLine() 에러 발생 줄 번호 10
getPrevious() 이전 예외 객체 (중첩 예외) null 또는 이전 Exception
catch(PDOException $e) { echo '오류: ' . $e->getMessage() . '<br>'; echo '코드: ' . $e->getCode() . '<br>'; echo '파일: ' . $e->getFile() . '<br>'; echo '줄번호: ' . $e->getLine() . '<br>'; die(); // 메시지 출력 후 종료 }
⚠ 운영 환경에서 getMessage()를 사용자 화면에 출력하면 DB 계정명·서버 정보가 노출된다. 운영에서는 에러를 로그 파일에만 기록하고, 사용자에게는 "서버 오류가 발생했습니다" 같은 일반 메시지를 표시할 것.

5 완전한 PDO 초기화 패턴
실무에서 바로 사용할 수 있는 PDO 연결 보일러플레이트

try/catch + setAttribute + EMULATE_PREPARES false를 모두 포함한 완전한 PDO 초기화 패턴이다. 이 구조를 외워두면 이후 모든 PHP + MySQL 프로젝트에서 재사용할 수 있다.

try { $pdo = new PDO( 'mysql:host=localhost;dbname=sampledb;charset=utf8mb4', 'root', '' ); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // ↑ 이 두 줄이 없으면 PDO는 에러를 조용히 무시 + PHP가 SQL을 흉내냄 // 항상 이 두 줄을 new PDO() 직후에 추가할 것 print "접속하였습니다."; } catch(PDOException $e) { die('접속 오류: ' . $e->getMessage()); } finally { // finally는 예외 여부 관계없이 실행 (PHP 5.5+) // 정리 작업이 필요하면 여기에 }

6 ATTR_EMULATE_PREPARES false — 왜 수동 설정인가
자동 에뮬레이션을 끄고 MySQL에게 맡기는 이유

PDO의 기본값은 PHP가 prepared statement를 에뮬레이션하는 것이다(true). 이 방식은 편리하지만 실제 MySQL의 prepared statement 기능을 사용하지 않아 일부 타입 처리가 부정확하고 완전한 SQL Injection 방어가 안 된다. false로 설정하면 MySQL이 직접 처리해 더 안전하고 정확하다.

※ 간단히 표현하면: ATTR_EMULATE_PREPARES=false는 "prepared statement를 PHP가 흉내 내지 말고, MySQL이 직접 실제로 실행해"라는 설정이다. 보안과 정확성이 향상된다.

7 catch 이후 흐름 — die vs 로깅 + finally
학습용 die()와 실무용 로깅의 차이

학습 코드에서는 에러 발생 시 die()로 즉시 종료하지만, 실제 서비스에서는 에러를 로그 파일에 기록하고 사용자에게는 일반적인 오류 메시지만 표시한다. finally 블록은 예외 발생 여부와 관계없이 항상 실행된다.

try { $pdo = new PDO(...); // DB 작업 } catch(PDOException $e) { // 학습: die()로 즉시 종료 die('오류: ' . $e->getMessage()); // 실무: 로그 기록 + 사용자에게 일반 메시지 // error_log($e->getMessage(), 3, '/var/log/php_errors.log'); // echo "서버 오류가 발생했습니다."; } finally { $pdo = null; // 예외 여부 관계없이 항상 접속 종료 }
finally 블록은 PHP 5.5+에서 지원. try나 catch에서 die가 있어도 finally는 항상 실행되므로 접속 종료 정리 작업에 안전하게 사용할 수 있다.

8 자주 보는 SQLSTATE 에러 코드
getCode()가 반환하는 에러 코드 해석

PDOException의 getCode()는 SQLSTATE 형식(5자리 영문+숫자)의 에러 코드를 반환한다. 앞 2자리가 에러 분류, 뒤 3자리가 세부 코드다. 자주 보는 코드를 알아두면 원인 파악이 빠르다.

SQLSTATE MySQL 에러번호 의미
HY000 1045 Access denied — 계정명/비밀번호 오류
HY000 1049 Unknown database — DB 이름 오타
HY000 2002 Connection refused — MySQL 서비스 꺼짐
23000 1062 Duplicate entry — PRIMARY KEY 또는 UNIQUE 중복
42S02 1146 Table doesn't exist — 없는 테이블에 쿼리
42000 1064 SQL syntax error — SQL 문법 오류

9 개발 환경 vs 운영 환경 에러 처리 분리
학습 코드와 실무 코드의 에러 처리 방식 차이

학습 환경에서는 에러 메시지를 화면에 바로 출력해서 원인을 파악하지만, 운영 환경에서는 에러 내용을 사용자에게 보여주면 DB 계정·서버 구조 등 민감 정보가 노출된다. 개발/운영 분기 처리를 습관으로 만들자.

define('ENV', 'development'); // 개발: 'development', 운영: 'production' catch(PDOException $e) { if(ENV === 'development') { die('[DEV] 접속 오류: ' . $e->getMessage()); // 개발: 상세 노출 } else { error_log($e->getMessage()); // 운영: 로그에만 기록 die('서버 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.'); } }

10 자주 하는 실수
실수 증상 해결
ATTR_ERRMODE 설정 누락 쿼리 에러 발생해도 아무 메시지 없이 진행됨 new PDO() 직후 ATTR_ERRMODE → ERRMODE_EXCEPTION 설정
catch 변수명을 $e로 축약 후 getMessage() 잊음 에러 발생 시 빈 화면 catch(PDOException $e) { die($e->getMessage()); } 완성 필수
try 밖에서 setAttribute 호출 접속 실패 시 $pdo가 없어 Fatal error setAttribute는 접속 성공 후 try 블록 안에서 호출
PDOException이 아닌 Exception으로 catch PDO 에러가 catch에 안 잡힘 catch(PDOException $e) 정확히 명시. PDOException은 Exception의 자식
의도적 에러 코드를 운영에 그대로 배포 내부 DB 정보(계정명, 에러 상세) 노출 운영 환경에서는 에러 메시지를 로그에만 기록하고 사용자에게는 일반 메시지 표시

핵심 한 줄 요약

try { new PDO() } catch(PDOException $e)PDO 접속 에러를 예외로 잡는 표준 패턴
ATTR_ERRMODE → ERRMODE_EXCEPTIONPDO 기본값(SILENT)을 바꿔 에러 시 예외를 던지도록 설정 — 필수
ATTR_EMULATE_PREPARES = falsePHP 에뮬레이션 끄고 MySQL이 직접 처리 — 보안·정확성 향상
$Exception->getMessage()PDOException 객체에서 에러 메시지 문자열 추출
finally { $pdo = null; }예외 여부 관계없이 항상 실행 — 접속 종료 정리 작업에 안전
SQLSTATE HY000/23000/42S02접속실패/중복키/없는테이블 — getCode()로 확인 후 원인 파악

Tags

#PHP PDO 예외처리 #setAttribute #ERRMODE_EXCEPTION #PDOException #try catch PHP #ATTR_EMULATE_PREPARES #getMessage #PHP DB 에러 #PDO 에러모드 #PHP 예외처리 #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
PHP PDO 예외처리, setAttribute, ERRMODE_EXCEPTION, PDOException, try catch PHP, ATTR_EMULATE_PREPARES, getMessage, PHP DB 에러, PDO 에러모드, PHP 예외처리
반응형

댓글