Error Reporting & Levels
PHP doesn't treat "something went wrong" as a single, uniform event. Instead it classifies problems into levels — a typo'd array key is very different from calling an undefined function — and gives you fine-grained control over which of those levels actually get reported. That control lives in the error_reporting() function (or the matching error_reporting ini directive), and it's one of the first things worth understanding well, because getting it wrong is the difference between catching bugs early and shipping a page that silently does the wrong thing.
The error level constants
Each level is represented by a bitmask constant, and error_reporting() accepts a combination of them joined with bitwise operators. The most commonly used ones:
Constant | Meaning |
|---|---|
| Fatal run-time errors that halt execution. |
| Run-time warnings (non-fatal) -- execution continues. |
| Notices about likely mistakes, like reading an undefined variable. |
| Code relying on a feature scheduled for removal in a future PHP version. |
| Suggestions for forward-compatible code (largely folded into other levels since PHP 8). |
| Every level above, combined -- the recommended setting during development. |
Setting the reporting level at runtime
<?php // Report absolutely everything -- the recommended development default. error_reporting(E_ALL); // Report everything except deprecation notices. error_reporting(E_ALL & ~E_DEPRECATED); // Report only real errors and warnings, skip notices. error_reporting(E_ERROR | E_WARNING);
The bitwise operators matter here: & combined with ~ (bitwise NOT) is how you say "everything except this one level," and | (bitwise OR) is how you combine specific levels. Passing a plain integer instead of these constants works but produces unreadable, hard-to-maintain configuration — always spell out the constants.
display_errors vs log_errors
error_reporting() only decides which levels are considered reportable at all. Two separate ini settings decide what happens to a reportable error: display_errors controls whether it's printed into the HTTP response (or CLI output), and log_errors controls whether it's written to the configured error log (error_log ini setting, or the web server's log by default). These are independent switches — you can have both on, both off, or just one.
A typical development php.ini
error_reporting = E_ALL display_errors = On log_errors = On error_log = /var/log/php/dev-errors.log
A typical production php.ini
error_reporting = E_ALL display_errors = Off log_errors = On error_log = /var/log/php/app-errors.log
Notice error_reporting stays at E_ALL in both cases. Turning reporting itself down in production is a common mistake — you still want every level recorded in the log so you can find bugs, you just don't want the display of them reaching a browser. The setting that should change between environments is display_errors, not error_reporting.
Setting the level from inside a script
While ini files are the normal place to configure this for a whole application, error_reporting() and ini_set() can also adjust behavior for a single script or even temporarily around one risky block of code.
Temporarily silencing notices around a legacy include
<?php $previousLevel = error_reporting(E_ALL & ~E_NOTICE); require __DIR__ . '/legacy/report-generator.php'; // Restore full reporting for the rest of the request. error_reporting($previousLevel);
error_reporting()decides which severities (E_ERROR,E_WARNING,E_NOTICE,E_DEPRECATED, ...) are considered reportable.E_ALLis the recommended level in every environment -- what differs between environments is what happens next.display_errorscontrols whether a reportable error is printed into the response; keep thisOffin production.log_errors(witherror_log) controls whether it is written to a log file; keep thisOneverywhere.Bitwise
|combines levels,& ~excludes a level from a combination.