본문 바로가기

비개발자의 개발 일지

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

시리즈 보기
php

PHP MYDB 접속 함수 — DSN · setAttribute 2가지 설정 · return $pdo 완전 정리

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

 

 

Web Development · PHP PDO

PHP MYDB 접속 함수 — DSN · setAttribute 2가지 설정 · return $pdo 완전 정리

PDO 접속 함수의 해부 — DSN 문자열 구조, 오류 모드·에뮬레이션 비활성화 2가지 설정, return의 필요성, 함수 분리의 이점
시작 오늘 분석할 코드

MYDB.php는 db_connect() 함수 하나로 구성된 공통 DB 접속 모듈이다. 43-2의 list.php·updateform.php 모두 이 함수를 require_once로 불러와 2줄로 DB 접속을 완료한다.

<?php function db_connect() { $db_user = "root"; $db_pass = ""; $db_host = "localhost"; $db_name = "sampledb"; $db_type = "mysql"; $dsn = "$db_type:host=$db_host;dbname=$db_name;charset=utf8"; try { $pdo = new PDO($dsn, $db_user, $db_pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } catch (PDOException $Exception) { die('오류: ' . $Exception->getMessage()); } return $pdo; } ?>
용어 핵심 용어 정리
DSNData Source Name — DB 종류·호스트·DB명·문자셋을 하나의 문자열로 표현
setAttributePDO 동작 방식을 설정하는 메서드 — 에러 처리 방식, SQL 에뮬레이션 등 제어
ERRMODE_EXCEPTIONPDO 에러를 예외로 던지도록 설정 — try-catch로 잡아 처리 가능
EMULATE_PREPARES falsePHP가 아닌 MySQL 드라이버가 직접 prepared statement 처리 — 타입 안정성 향상
charset=utf8DSN에 문자셋 지정 — 한글 깨짐 방지. utf8mb4 권장 (이모지 등 4바이트 지원)
return $pdo함수 스코프의 PDO 객체를 호출부로 반환 — 없으면 null 반환으로 prepare() 에러
die()메시지 출력 후 즉시 스크립트 종료 — DB 접속 실패 시 null로 연쇄 에러 방지
require_once파일 포함 + 중복 방지 — 함수 중복 정의 Fatal Error 차단

1 DSN 문자열 구조 — 큰따옴표 안의 변수 치환

DSN은 "$db_type:host=$db_host;dbname=$db_name;charset=utf8"처럼 큰따옴표 안에 변수를 직접 넣는다. PHP는 큰따옴표 문자열 안의 $변수명을 자동으로 값으로 치환한다. 작은따옴표 문자열에서는 변수 치환이 일어나지 않는다.

$db_type = "mysql"; $db_host = "localhost"; $db_name = "sampledb"; // 큰따옴표 — 변수 치환 됨 $dsn = "$db_type:host=$db_host;dbname=$db_name;charset=utf8"; // 결과: "mysql:host=localhost;dbname=sampledb;charset=utf8" // 작은따옴표 — 변수 치환 안 됨 (그대로 출력) $dsn = '$db_type:host=$db_host;dbname=$db_name;charset=utf8'; // 결과: "$db_type:host=$db_host;dbname=$db_name;charset=utf8" (에러)

2 setAttribute 2가지 — 왜 둘 다 필요한가
설정 의미 없을 때
ATTR_ERRMODE ERRMODE_EXCEPTION 오류를 예외(PDOException)로 던짐 오류가 조용히 넘어가 디버그 어려움 — 기본값 ERRMODE_SILENT
ATTR_EMULATE_PREPARES false MySQL 드라이버 직접 처리 PHP가 대신 처리 — 타입 변환 불정확 가능 (정수가 문자열로 처리)
※ EMULATE_PREPARES false + PARAM_INT 조합 시 PHP가 bindValue에서 지정한 타입을 MySQL 레벨에서 강제. EMULATE_PREPARES true이면 MySQL 드라이버가 아닌 PHP가 문자열 치환으로 처리하여 타입 보장이 약해진다.

3 43-2에서의 역할 — list.php와 updateform.php가 함께 사용

43-2 패턴에서 list.php는 DELETE/INSERT/UPDATE/SELECT 모두 처리하고, updateform.php는 수정 전 SELECT만 처리한다. 두 파일 모두 MYDB.php를 require_once로 로드해 동일한 db_connect() 함수를 사용한다. 접속 정보는 MYDB.php 1곳만 수정하면 전파된다.

1
updateform.php 시작 — require_once("MYDB.php")db_connect() 함수 정의 로드 (SELECT용)
2
list.php 시작 — require_once("MYDB.php")이미 로드됐으면 무시 (중복 로드 방지) — DELETE/INSERT/UPDATE/SELECT 모두 처리
3
$pdo = db_connect()각 파일에서 독립적으로 PDO 객체 생성 — 파일별 연결 1개씩
4
$pdo->prepare() / query() 등 각자 사용같은 함수에서 받은 PDO지만 각자의 파일 스코프에서 독립 동작

 

반응형

 

4 utf8 vs utf8mb4 — charset 선택

DSN의 charset=utf8은 MySQL의 utf8 문자셋인데, MySQL의 utf8은 3바이트만 지원해 이모지(4바이트)를 저장하지 못한다. 실무에서는 charset=utf8mb4를 권장한다. 교육 코드에서는 단순화를 위해 utf8을 사용한 것이다.

⚠ MySQL의 utf8은 완전한 유니코드 UTF-8이 아니다 — 3바이트 제한으로 이모지(🎉), CJK 확장 한자 등 4바이트 문자를 저장 시 에러 또는 데이터 손실. 새 프로젝트는 반드시 utf8mb4 사용.
// 교육 코드 $dsn = "mysql:host=localhost;dbname=sampledb;charset=utf8"; // 실무 권장 $dsn = "mysql:host=localhost;dbname=sampledb;charset=utf8mb4";

5 자주 하는 실수
실수 증상 해결
return $pdo 누락 $pdo = db_connect() 결과 null → prepare() 호출 시 에러 함수 마지막 줄에 return $pdo 필수
ATTR_ERRMODE 설정 누락 SQL 에러가 조용히 넘어감 — 디버그 어렵고 데이터 불일치 발생 setAttribute(ATTR_ERRMODE, ERRMODE_EXCEPTION) 항상 설정
charset=utf8 (이모지 사용 시) 이모지 저장 에러 또는 데이터 손실 charset=utf8mb4로 변경 + DB/테이블도 utf8mb4로 설정
DSN에 작은따옴표 사용 (변수 포함) $db_host 등이 변수 치환 안 됨 — 리터럴 문자열 "$db_host"가 DSN에 들어감 변수 포함 DSN은 큰따옴표 사용
require 대신 require_once 미사용 다중 포함 시 "Cannot redeclare db_connect()" Fatal Error require_once("MYDB.php")로 중복 방지

6 ATTR_DEFAULT_FETCH_MODE — 매번 FETCH_ASSOC 넘기지 않는 방법

fetch(PDO::FETCH_ASSOC)를 매번 호출하는 것이 번거롭다면 PDO 연결 시 기본 fetch 모드를 설정할 수 있다. ATTR_DEFAULT_FETCH_MODE를 FETCH_ASSOC으로 지정하면 fetch() 호출 시 인수 없이도 항상 컬럼명 키 배열로 반환된다.

// db_connect()에 추가하면 편리한 설정 $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); // 설정 전: 매번 FETCH_ASSOC 명시 $row = $stmh->fetch(PDO::FETCH_ASSOC); // 설정 후: 인수 없이도 FETCH_ASSOC 동작 $row = $stmh->fetch();
설정 fetch() 기본 반환 특징
미설정 (기본) FETCH_BOTH — 컬럼명 + 인덱스 양쪽 메모리 2배 사용, 보통 불필요
ATTR_DEFAULT_FETCH_MODE = FETCH_ASSOC 컬럼명 키 배열만 $row['last_name'] 형태로 항상 접근 가능
ATTR_DEFAULT_FETCH_MODE = FETCH_NUM 인덱스 배열만 $row[1] 형태 — 컬럼 순서에 의존적
※ 교육 코드에서는 fetch(PDO::FETCH_ASSOC)를 매번 명시해 코드에서 반환 형식을 바로 확인할 수 있게 했다. 실무에서는 ATTR_DEFAULT_FETCH_MODE를 db_connect() 안에 설정해 코드 간소화를 선택하는 경우가 많다.

7 PDO 생성자 4번째 인수 — 옵션 배열로 한 번에 설정

setAttribute를 2번 호출하는 대신, PDO 생성자의 4번째 인수로 옵션 배열을 넘기는 방법도 있다. 연결과 동시에 설정이 완료되어 코드가 간결해진다. 기능적으로 setAttribute를 따로 호출하는 것과 동일하다.

// 현재 방식 — setAttribute 2회 호출 $pdo = new PDO($dsn, $db_user, $db_pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // 동등한 방식 — 4번째 인수 옵션 배열로 한 번에 $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]; $pdo = new PDO($dsn, $db_user, $db_pass, $options);
※ 옵션 배열을 4번째 인수로 쓰면 ATTR_ERRMODE가 new PDO() 시점에 적용되어, PDO 생성자 자체의 에러도 예외로 잡을 수 있다는 미묘한 차이가 있다. 교육 코드에서는 명시적 setAttribute 방식을 선택해 설정 의도가 한 줄씩 명확히 보이도록 했다.

8 에러 처리 전략 비교 — die() vs 예외 재던지기 vs 로깅

교육 코드에서는 catch 안에서 die()로 즉시 종료한다. 실제 서비스에서는 에러를 로그에 기록하거나 사용자에게 친화적인 메시지를 보여주는 방식이 필요하다. 세 가지 전략을 비교해 상황에 맞는 선택을 할 수 있다.

전략 코드 예시 적합한 상황
die() 즉시 종료 die('오류: ' . $e->getMessage()) 교육용·로컬 개발 — 원인 빠르게 파악
로그 기록 후 종료 error_log($e->getMessage()); die('서버 오류') 운영 환경 — 사용자에게 에러 숨기고 로그로 추적
예외 재던지기 throw new RuntimeException($e->getMessage()) 라이브러리/프레임워크 — 상위 코드가 에러 처리
⚠ 운영 환경에서 die($e->getMessage())를 그대로 쓰면 DB 서버 주소·사용자명·비밀번호 힌트가 화면에 노출될 수 있다. 운영 서버에서는 반드시 로그 기록 + 사용자에게 일반 에러 메시지만 표시.

9 접속 정보 분리 — .env 파일 패턴 (실무 발전 방향)

교육 코드에서 $db_user, $db_pass 등이 MYDB.php 안에 하드코딩되어 있다. 실제 서비스에서는 Git에 비밀번호가 노출되는 문제가 생긴다. 접속 정보를 별도 설정 파일(.env)에 분리하고 MYDB.php에서 읽는 패턴이 실무 표준이다.

// .env 파일 (Git에 올리지 않음 — .gitignore에 추가) DB_USER=root DB_PASS=secretpassword DB_HOST=localhost DB_NAME=sampledb // MYDB.php에서 환경 변수로 읽기 $db_user = getenv('DB_USER') ?: 'root'; $db_pass = getenv('DB_PASS') ?: ''; // 또는 dotenv 라이브러리 사용 (vlucas/phpdotenv 등)
※ 교육 단계에서는 접속 정보를 파일에 직접 쓰는 것이 동작 확인에 편하다. 실제 프로젝트에서 코드를 공유하거나 GitHub에 올릴 예정이라면 .env 분리를 필수로 적용한다.

10 43-2 뼈대 암기 — db_connect()의 순서

43-2 폴더 제목 "뼈대 외워야함"의 핵심이다. db_connect() 안의 코드 흐름을 순서대로 외워두면 어떤 CRUD 프로젝트에서도 재사용할 수 있다. 이 함수 하나를 외워두면 list.php·updateform.php를 require_once로 연결하는 전체 패턴이 자동으로 따라온다.

db_connect() 암기 순서 (7단계)
  • ① 접속 정보 변수 5개: $db_user / $db_pass / $db_host / $db_name / $db_type
  • ② DSN 조합: "$db_type:host=$db_host;dbname=$db_name;charset=utf8"
  • ③ try { new PDO($dsn, $db_user, $db_pass) }
  • ④ setAttribute(ATTR_ERRMODE, ERRMODE_EXCEPTION) — 예외 모드
  • ⑤ setAttribute(ATTR_EMULATE_PREPARES, false) — 드라이버 직접 처리
  • ⑥ } catch(PDOException $e) { die('오류:' . $e->getMessage()); }
  • ⑦ return $pdo; — try-catch 밖, 함수 마지막 줄에 반드시 위치

이 7단계 흐름이 MYDB.php의 전부다. 각 단계의 역할과 순서를 이해하면 암기보다 자연스러운 재현이 가능해진다.


핵심 한 줄 요약

DSN = 큰따옴표 변수 치환"$db_type:host=$db_host;dbname=$db_name;charset=utf8" — 5개 변수 조합
setAttribute 2가지ERRMODE_EXCEPTION(예외모드) + EMULATE_PREPARES false(드라이버 직처리) 세트
return $pdo함수 스코프 PDO를 호출부로 전달 — 누락 시 null이 반환되어 prepare() 에러
die() on 접속 실패catch에서 즉시 종료 — null $pdo로 연쇄 에러 방지
require_once다중 포함 시 함수 재정의 Fatal Error 방지 — 43-2 파일들 모두 require_once 사용
charset=utf8mb4 (실무)교육 코드의 utf8은 3바이트 제한 — 이모지·확장 한자 저장 시 utf8mb4로 변경
.env 분리 (실무)DB 비밀번호를 코드에 하드코딩 금지 — 환경 변수나 .env 파일로 분리 후 .gitignore 처리

Tags

#PDO #PHP #MySQL #MYDB #db_connect #DSN #setAttribute #ERRMODE_EXCEPTION #EMULATE_PREPARES #require_once #접속함수 #PHP학습 #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
PDO, PHP, MySQL, MYDB, db_connect, DSN, setAttribute, ERRMODE_EXCEPTION, EMULATE_PREPARES, require_once
반응형

댓글