PHP 에러를 표시하려면 스크립트 맨 위에 다음 줄을 넣으세요: ini_set('display_errors', '1');와 error_reporting(E_ALL);. 첫 번째는 PHP가 에러 메시지를 출력하게 하고, 두 번째는 경고와 deprecation을 포함한 모든 종류의 에러를 보고하게 합니다.
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
이렇게 해 두면 설정된 적 없는 변수를 읽는 것 같은 실수가 조용히 실패하는 대신 파일과 줄 번호가 담긴 메시지를 출력합니다.
Warning: Undefined variable $total in /home/index.php on line 7
인자 없이 호출한 error_reporting()은 현재 설정을 숫자로 반환합니다. Run을 눌러 레벨을 설정하고 그것을 다시 이름으로 풀어 보세요.
각 에러 유형은 비트 하나이므로 E_ALL & ~E_DEPRECATED는 "deprecation을 제외한 전부"라는 뜻입니다. 첫 줄을 error_reporting(E_ERROR | E_WARNING);로 바꾸고 다시 실행해 보세요.
php.ini에서 에러 표시
스크립트 안의 설정은 스크립트가 실행되기 시작한 뒤에만 적용됩니다. 구문 에러를 포함해 모든 스크립트에서 에러를 표시하려면 php.ini를 수정하세요(php --ini로 찾을 수 있습니다).
; Development
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
수정한 뒤에는 Apache나 PHP-FPM을 재시작하세요. php -S 내장 서버와 명령줄은 시작할 때마다 파일을 읽습니다. php.ini에 접근할 수 없는 공유 호스팅에서는 mod_php를 쓰는 Apache가 .htaccess 줄도 받아들입니다.
php_flag display_errors on
php_value error_reporting -1
-1은 모든 비트를 설정하므로 E_ALL과 같습니다.
에러 레벨
| 상수 | 발생 원인 | 스크립트 중단 |
|---|---|---|
E_ERROR | 메모리 부족 같은 치명적 런타임 에러 | 예 |
E_PARSE | 파일의 구문 에러 | 예 |
E_WARNING | 정의되지 않은 변수나 배열 키, include의 파일 누락 | 아니요 |
E_NOTICE | 사소한 문제(PHP 8에서는 거의 남아 있지 않음) | 아니요 |
E_DEPRECATED | 향후 PHP 버전에서 거부될 코드 | 아니요 |
E_USER_* | trigger_error()로 직접 발생시킨 에러 | E_USER_ERROR만 |
E_ALL | 여기 없는 코어 및 컴파일 에러를 포함한 모든 레벨 |
PHP 8.0은 예전 경고 다수를 예외로 바꾸었습니다. /로 0으로 나누기와 내장 함수에 잘못된 타입 전달은 이제 Error 하위 클래스를 던지며, 이는 PHP 7부터 정의되지 않은 함수 호출이 그랬던 것과 같습니다. 세 가지 모두 잡을 수 있습니다.
예외는 try와 catch에서 다룹니다. 경고, notice, deprecation은 여전히 여기서 설명하는 에러 보고 시스템을 거칩니다.
에러를 표시하지 말고 로그로 남기기
운영 중인 사이트에서는 방문자가 에러 메시지를 보면 안 됩니다. 경로, SQL, 코드가 드러나기 때문입니다. 대신 로그 파일에 기록하세요.
; Production
display_errors = Off
log_errors = On
error_log = /var/log/php/app-errors.log
error_reporting = E_ALL
운영 환경에서도 error_reporting = E_ALL을 유지하세요. 레벨을 낮춘다고 에러가 사라지지 않고, 에러 소식을 듣지 못하게 될 뿐입니다. 직접 남기는 메시지도 error_log()로 같은 로그에 보낼 수 있습니다.
<?php
error_log("Payment failed for order 1042");
테스트하는 동안 파일을 지켜보세요: tail -f /var/log/php/app-errors.log.
set_error_handler로 경고를 예외로 바꾸기
set_error_handler는 경고, notice, deprecation에 대한 PHP 기본 처리를 내 함수로 대체합니다. 흔한 패턴은 이들을 모두 ErrorException으로 바꾸는 것으로, 그러면 빠뜨린 배열 키도 다른 예외처럼 코드를 멈추고 잡을 수 있게 됩니다.
핸들러는 첫 번째 인자로 에러 레벨을 받으므로 레벨별로 다르게 처리할 수 있습니다. 이 핸들러는 deprecation은 로그만 남기고 나머지는 모두 예외로 바꿉니다.
치명적 에러와 구문 에러는 그 뒤에 스크립트가 계속될 수 없으므로 핸들러에 도달하지 않습니다. 이를 기록하려면 error_get_last()를 읽는 종료 함수를 등록하세요.
error_get_last로 마지막 에러 읽기
어떤 함수는 false를 반환하고 이유는 경고로만 알립니다. 예를 들어 없는 파일에 대한 file_get_contents입니다. error_get_last()는 그 경고를 배열로 반환하므로, 직접 만든 메시지를 보여 주고 싶을 때 유용합니다.
호출 앞의 @ 연산자는 그 표현식 하나의 메시지를 억제합니다. 여기처럼 바로 뒤에서 결과를 확인할 때만 아껴서 쓰세요. 그냥 붙인 @는 버그를 숨길 뿐입니다.
흔한 실수: 에러 표시를 켰는데 페이지가 여전히 빈 화면
ini_set('display_errors', '1')을 추가했는데도 흰 페이지가 보인다면 아마 구문 에러일 것입니다. PHP는 첫 줄을 실행하기 전에 파일 전체를 파싱하므로, ;나 } 하나가 빠지면 ini_set이 실행되기 전에 모든 것이 멈춥니다. 항상 메시지를 출력하는 터미널에서 파일을 검사하세요.
php -l index.php
Errors parsing index.php
PHP Parse error: syntax error, unexpected token "," in index.php on line 2
줄 번호는 PHP가 포기한 지점을 가리키며, 실제 실수의 다음 줄인 경우가 많습니다. 고친 뒤 No syntax errors detected가 나올 때까지 php -l을 다시 실행하고, 페이지를 새로 고치세요.
자주 묻는 질문
PHP에서 모든 에러를 표시하려면 어떻게 하나요?
스크립트 맨 위에 ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL);를 추가하거나, php.ini에서 display_errors = On과 error_reporting = E_ALL로 설정하고 웹 서버나 PHP-FPM을 재시작하세요.
PHP 페이지가 하얀 빈 화면으로 나오는 이유는?
display_errors가 꺼진 상태에서 치명적 에러가 스크립트를 멈춰서 아무것도 출력되지 않은 것입니다. 에러 표시를 켜거나 에러 로그를 읽어(예: error_log가 가리키는 파일에 tail -f) 메시지와 줄 번호를 확인하세요.
ini_set('display_errors', 1)을 써도 구문 에러가 안 보이는 이유는?
구문 에러는 파일의 어떤 줄도 실행되기 전에 PHP를 멈추므로 ini_set 호출이 실행되지 않습니다. php.ini에서 display_errors를 설정하거나, ini_set을 작은 파일에 넣고 그 파일에서 문제의 파일을 include하세요.
운영 환경에서 display_errors를 켜야 하나요?
아니요. 에러 메시지는 방문자에게 파일 경로와 코드 세부 정보를 노출합니다. 운영 환경에서는 display_errors = Off, log_errors = On, 그리고 error_log 경로를 쓰고, 문제가 계속 기록되도록 error_reporting = E_ALL은 유지하세요.
error_reporting(0)은 무엇을 하나요?
스크립트의 나머지 부분에서 모든 에러 유형의 보고를 끄므로, 경고는 물론 치명적 에러도 메시지를 내지 않습니다. 문제를 고치는 것이 아니라 숨기는 것이므로, 에러를 묵살하기보다 로그로 남기는 편이 좋습니다.