Errors are useful evidence when they reach the right person in the right form. A developer needs details to fix a warning; a visitor needs a clear failure message that does not expose paths, credentials, or SQL. PHP's error reporting, display settings, logging, and exception handling are related but distinct tools. This reference explains those boundaries and shows a small request-ID logging pattern. You will distinguish expected validation results from failures, avoid global suppression, and learn why a runtime error handler cannot catch every possible startup problem. Good logs should make incidents easier to diagnose without becoming another store of secrets.
Separate reporting, display and logging
error_reporting(E_ALL) selects a broad set of diagnostics, including warnings and deprecations. display_errors controls whether PHP prints them into the response, while log_errors controls logging under the runtime configuration. In development, visible details can help, but production responses should normally avoid them. Set production behavior in php.ini or the deployment configuration because parse and startup failures may happen before runtime ini_set() calls. A JSON endpoint with an echoed warning becomes invalid JSON, even if the warning did not stop execution. Downloads can be corrupted the same way. Fix the error and keep diagnostics in a private channel rather than relying on the browser to display a clean page despite stray output.
Distinguish exceptions from traditional diagnostics
Exceptions and Error objects implement Throwable and can be caught at an appropriate boundary. Traditional warnings and notices use PHP's error-reporting mechanism. set_error_handler() can intercept supported categories and optionally convert selected ones to ErrorException, but it does not handle every startup, parse, or fatal condition. If a handler returns false, normal handling can continue according to the contract. Respect the active reporting policy where appropriate and avoid turning every expected warning into a misleading business error. Choose one application policy and test it. A top-level exception handler can produce a generic response and log the failure, but it should not pretend the request successfully completed after an unhandled exception.
Log an operation and correlation identifier
A request identifier links a user-visible failure to private diagnostics. Generate or validate it under the server's policy; do not trust an arbitrary incoming value without bounds and character rules. Log an operation name, safe error class or code, duration where useful, and the request ID. This is often more actionable than a giant unstructured dump of every variable. Structured JSON logs can simplify searching and aggregation, but encoding must also handle malformed strings safely. Keep timestamps and timezone conventions consistent across services. A visitor can report an incident identifier without receiving a stack trace. Avoid placing confidential user content into the identifier or using sequential IDs that reveal more than needed.
Keep sensitive values out of logs
Passwords, access tokens, session cookies, reset links, SMTP credentials, and full connection strings should not appear in routine logs. Submitted text may contain private information or malicious line breaks, so log a safe summary instead of raw bodies. A database exception can include query values and schema details; decide which portions are appropriate for restricted diagnostics. Redact known secret fields and apply a retention policy. Restrict who can read logs and where they are exported. 'Server-side' does not mean harmless: logs can be downloaded, copied into support tools, or retained far longer than application data. Test error paths specifically for leaked secrets rather than reviewing only normal successful responses.
Make expected outcomes visible without noisy errors
Invalid form input is usually a validation result, not a server incident. A missing product can be a normal 404 outcome. A recognized duplicate constraint can be a conflict under the feature's rules. Log these at a suitable level if useful, but avoid filling error dashboards with ordinary behavior. Unexpected database outages, filesystem failures, and uncaught exceptions deserve operational attention. Define severity levels and alert conditions according to user impact. Repeated warnings should be fixed instead of ignored until they obscure a real incident. Track deprecations during development and upgrades so a runtime change does not introduce production failures unexpectedly.
Operate the logging destination reliably
A file log needs writable storage, safe permissions, rotation, and disk monitoring. Hosted environments may prefer stderr or platform collection rather than a local file that disappears between instances. A failing log destination can leave you with no incident evidence, so verify it under the actual service account. Avoid recursively throwing from an error handler when logging itself fails. Keep an emergency fallback appropriate to the platform. Test one controlled failure in staging and verify both the generic response and the private record. Review whether the log system groups duplicate events and whether request identifiers survive across queue jobs or service calls. Useful observability is a deployed behavior, not only a logging line in source code.
Practice task and worked solution
Review a JSON API that echoes exception messages and logs the complete POST array. The solution disables production display at startup, returns a structured generic error with a request identifier, and logs only safe operation metadata. Remove passwords, tokens, and confidential payloads from the logging path. Distinguish validation failures from unexpected infrastructure failures so the API uses appropriate statuses. Test a simulated database outage, malformed JSON, and a log-destination permission failure in an isolated environment. Verify the response remains valid JSON and operators can find the corresponding event. Document log access and retention rather than assuming all diagnostics can be stored indefinitely.
Continue learning
Review exceptions, security, and REST APIs.
The PHP error configuration reference explains display and logging directives.
Error Reporting and Logging Examples
Each example shows the code, the output it produces and what each part does.
Return a generic error with a request identifier
This fixed CLI demonstration simulates a failure, writes a restricted diagnostic through error_log(), and prints a safe public-style message.
The displayed reference is random on each run. The private log includes the operation, identifier, and error class, without a password, submitted body, or stack trace in the public message. The actual log destination depends on PHP configuration.
<?php
$requestId = bin2hex(random_bytes(8));
try {
throw new RuntimeException('Simulated storage failure');
} catch (Throwable $error) {
$record = [
'event' => 'profile_save_failed',
'request_id' => $requestId,
'error_class' => get_class($error),
];
error_log(json_encode($record, JSON_THROW_ON_ERROR));
echo 'Unable to save. Reference: ' . $requestId;
}Unable to save. Reference: generated request identifier
Private log: profile_save_failed with the same identifier and RuntimeException class.Error Reporting and Logging FAQ
Does E_ALL display errors?
No. error_reporting(E_ALL) selects which diagnostics PHP reports; display and logging are separate settings. display_errors decides whether they appear in the output and log_errors whether they go to the log. In production, report everything, log it and display nothing.
Can set_error_handler catch every failure?
No. Several startup and fatal categories are outside its reach, including parse errors and fatal errors such as running out of memory. Use set_exception_handler() for uncaught exceptions and register_shutdown_function() with error_get_last() to record fatal errors.
Should validation errors be exceptions?
Choose a clear application contract. Validation errors are often ordinary results, such as a list of field messages to show in a form, and returning them is simpler than throwing. Throwing suits a value that should never reach a function, such as a negative quantity passed to a domain method.
Is logging raw input useful?
Rarely. It can leak secrets, such as passwords, tokens and card numbers, and create noise that hides real problems. Log bounded safe context instead: the request ID, the user ID, the field names that failed and a short, sanitised description.
Error Reporting and Logging Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
A log stores the entire signup POST body. What should change?
Error Reporting and Logging Quiz
2 questions to check what you learned.
Which setting selects reported PHP diagnostic categories?
- error_reporting
- The HTML title
- PDO::FETCH_ASSOC
- The browser width
What should a public failure contain?
- Raw credentials
- A safe message and useful reference identifier
- A full session cookie
- Every SQL statement