To show PHP errors, put these lines at the top of your script: ini_set('display_errors', '1'); and error_reporting(E_ALL);. The first makes PHP print error messages, the second makes it report every kind of error, including warnings and deprecations.
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
With that in place, a mistake such as reading a variable that was never set prints a message with the file and line number instead of failing silently:
Warning: Undefined variable $total in /home/index.php on line 7
error_reporting() called with no argument returns the current setting as a number. Press Run to set a level and decode it back into names:
Each error type is one bit, so E_ALL & ~E_DEPRECATED means "everything except deprecations". Change the first line to error_reporting(E_ERROR | E_WARNING); and run it again.
Display errors in php.ini
A setting in the script only applies once the script starts running. To show errors for every script, including parse errors, change php.ini (find it with php --ini):
; Development
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
Restart Apache or PHP-FPM after editing. The php -S built-in server and the command line read the file on every start. On shared hosting without php.ini access, Apache with mod_php also accepts .htaccess lines:
php_flag display_errors on
php_value error_reporting -1
-1 sets every bit, which is the same as E_ALL.
The error levels
| Constant | What triggers it | Stops the script |
|---|---|---|
E_ERROR | Fatal runtime error, such as running out of memory | yes |
E_PARSE | Syntax error in the file | yes |
E_WARNING | Undefined variable or array key, missing file in include | no |
E_NOTICE | Minor issues (few remain in PHP 8) | no |
E_DEPRECATED | Code that a future PHP version will reject | no |
E_USER_* | Errors you raise with trigger_error() | only E_USER_ERROR |
E_ALL | Every level, including core and compile errors not listed here |
PHP 8.0 turned many old warnings into exceptions: dividing by zero with / and passing the wrong type to a built-in function now throw an Error subclass, the same way calling an undefined function has since PHP 7. You can catch all three:
Exceptions are covered in try and catch. Warnings, notices and deprecations still go through the error reporting system described here.
Log errors instead of displaying them
On a live site, visitors should never see error messages: they reveal paths, SQL and code. Write them to a log file instead:
; Production
display_errors = Off
log_errors = On
error_log = /var/log/php/app-errors.log
error_reporting = E_ALL
Keep error_reporting = E_ALL in production. Turning it down does not make the errors go away, it only stops you from hearing about them. Your own messages can go to the same log with error_log():
<?php
error_log("Payment failed for order 1042");
Then watch the file while you test: tail -f /var/log/php/app-errors.log.
Turn warnings into exceptions with set_error_handler
set_error_handler replaces PHP's default handling of warnings, notices and deprecations with your own function. A common pattern converts every one into an ErrorException, so a forgotten array key stops the code like any other exception and can be caught:
The handler receives the error level as its first argument, so it can treat levels differently. This one only logs deprecations and turns everything else into an exception:
Fatal errors and parse errors never reach the handler, because the script cannot continue after them. To record those, register a shutdown function that reads error_get_last().
Read the last error with error_get_last
Some functions return false and report the reason only as a warning, for example file_get_contents on a missing file. error_get_last() returns that warning as an array, which is useful when you want to show your own message:
The @ operator in front of the call suppresses the message for that one expression. Use it sparingly and only when you check the result right after, as here; an @ on its own only hides bugs.
Common mistake: errors are on, but the page is still blank
If you added ini_set('display_errors', '1') and still see a white page, the error is probably a parse error. PHP parses the whole file before running the first line, so a missing ; or } stops everything before ini_set runs. Check the file from the terminal, which always prints the message:
php -l index.php
Errors parsing index.php
PHP Parse error: syntax error, unexpected token "," in index.php on line 2
The line number points at where PHP gave up, which is often the line after the real mistake. Fix it, run php -l again until it says No syntax errors detected, then reload the page.
Frequently Asked Questions
How do I display all errors in PHP?
Add ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); at the very top of the script, or set display_errors = On and error_reporting = E_ALL in php.ini and restart the web server or PHP-FPM.
Why does my PHP page show a blank white screen?
A fatal error stopped the script while display_errors is off, so nothing was printed. Turn errors on (or read the error log, for example with tail -f on the file error_log points to) to see the message and line number.
Why does ini_set('display_errors', 1) not show my parse error?
A parse error stops PHP before any line of the file runs, so the ini_set call never happens. Set display_errors in php.ini, or put the ini_set in a small file that then includes the broken one.
Should display_errors be on in production?
No. Error messages reveal file paths and code details to visitors. In production use display_errors = Off, log_errors = On and an error_log path, and keep error_reporting = E_ALL so problems are still recorded.
What does error_reporting(0) do?
It turns off reporting of every error type for the rest of the script, so warnings and even fatal errors produce no message. It hides problems rather than fixing them; prefer logging errors instead of silencing them.