getMessage(), $throwable->getFile(), $throwable->getLine() ); $forceDebugLog($message); $forceDebugLog($throwable->getTraceAsString()); if ($forceDebugEnabled) { http_response_code(500); echo '
' . htmlspecialchars($message . "\n" . $throwable->getTraceAsString(), ENT_QUOTES, 'UTF-8') . ''; } }); // Capture fatal shutdown errors (E_ERROR, E_PARSE, etc.) and surface them to stderr. register_shutdown_function(static function () use ($forceDebugLog, $forceDebugEnabled): void { $error = error_get_last(); if ($error === null) { return; } $fatalTypes = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR]; if (!in_array($error['type'], $fatalTypes, true)) { return; } $message = sprintf( '[force-debug] Fatal error (%s): %s in %s:%d', $error['type'], $error['message'], $error['file'], $error['line'] ); $forceDebugLog($message); if ($forceDebugEnabled) { http_response_code(500); echo '
' . htmlspecialchars($message, ENT_QUOTES, 'UTF-8') . ''; } }); if ($forceDebugEnabled) { error_reporting(E_ALL); ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); $forceDebugLog('[force-debug] FORCE_DEBUG_ERRORS is enabled — stack traces will be sent to clients. Disable this in production.'); }