In a production PHP application, error logging to the screen should be disabled. YOu don’t want users seeing that. What happens if exceptions or errors occur? You still need to access them. One answer is to write all exceptions and errors to a log file.

Here is how you can output all errors and exceptions to a log file.

Note: By setting error handlers, you can customize the message, dump stack traces, redact sensitive information and send your messages to alternate channels. This is not possible when using error_log by itself.

<?php

// Set error reporting to catch everything
error_reporting(E_ALL);
ini_set('display_errors', 0);

// Log file location
define('ERROR_LOG_FILE', __DIR__ . '/error.log');
define('COMPILE_ERROR_LOG_FILE', __DIR__ . '/compile_error.log');

// You might ask why not just use error_log
// By doing this you can do other things when errors occur
// Error handler
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
    // redact possible credit card info
    $errstr = preg_replace('/([0-9]{12})([0-9]{4})/', str_repeat('*', 12) . '$2', $errstr);
    $msg = "[" . date('Y-m-d H:i:s') . "] ERROR $errno: $errstr in $errfile on line $errline\\n";
    error_log($msg, 3, ERROR_LOG_FILE);
    // Do other stuff?
    // Don't execute PHP internal error handler
    return true;
});

// Exception handler
set_exception_handler(function ($exception) {
    // Some examples of message customization
    // redact possible credit card info
    $errstr = preg_replace('/([0-9]{12})([0-9]{4})/', str_repeat('*', 12) . '$2', $exception->getMessage());
    $code = $exception->getCode();
    if ( $code ) {
        $errstr .= "\\nCode={$code}";
    }

    $msg = "[" . date('Y-m-d H:i:s') . "] EXCEPTION: " . $errstr .
           " in " . $exception->getFile() . " on line " . $exception->getLine() . "\\n" .
           $exception->getTraceAsString() . "\\n";
    error_log($msg, 3, ERROR_LOG_FILE);
    // Do other stuff like send to Slack, Discord
});

// Fatal error shutdown handler
register_shutdown_function(function () {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        $msg = "[" . date('Y-m-d H:i:s') . "] FATAL ERROR {$error['type']}: {$error['message']} in {$error['file']} on line {$error['line']}\\n";
        /// write compile errors somewhere else
        $file = ($error['type'] == E_COMPILE_ERROR) ? COMPILE_ERROR_LOG_FILE : ERROR_LOG_FILE;
        error_log($msg, 3, $file);
    }
});