PHPError Reporting & Levels

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

E_ERROR

Fatal run-time errors that halt execution.

E_WARNING

Run-time warnings (non-fatal) -- execution continues.

E_NOTICE

Notices about likely mistakes, like reading an undefined variable.

E_DEPRECATED

Code relying on a feature scheduled for removal in a future PHP version.

E_STRICT

Suggestions for forward-compatible code (largely folded into other levels since PHP 8).

E_ALL

Every level above, combined -- the recommended setting during development.

Setting the reporting level at runtime

PHP
<?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

PHP
error_reporting = E_ALL
display_errors = On
log_errors = On
error_log = /var/log/php/dev-errors.log

A typical production php.ini

PHP
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
<?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);
Note
Prefer to fix the underlying notice-generating code rather than habitually silencing levels. Reaching for `error_reporting()` to hide a specific legacy file, as above, should be a temporary bridge while that file gets cleaned up — not a permanent pattern applied across the whole application.
Never enable display_errors in production
With `display_errors = On`, an uncaught error or an unhandled exception renders directly into the HTTP response — including the full filesystem path of the script, the exact line number, and often a chunk of the call stack. That's a roadmap for anyone probing your server, and it can also leak values like database hostnames embedded in a connection-string error message. Production servers should always run with `display_errors = Off` and `log_errors = On`, and show users a generic error page instead.
  • error_reporting() decides which severities (E_ERROR, E_WARNING, E_NOTICE, E_DEPRECATED, ...) are considered reportable.

  • E_ALL is the recommended level in every environment -- what differs between environments is what happens next.

  • display_errors controls whether a reportable error is printed into the response; keep this Off in production.

  • log_errors (with error_log) controls whether it is written to a log file; keep this On everywhere.

  • Bitwise | combines levels, & ~ excludes a level from a combination.

Tip
A quick way to sanity-check a production server's configuration is `php -i | grep display_errors` (or checking `phpinfo()` output) — if it reports anything other than `Off`, that's worth fixing before anything else on the error-handling checklist.