Setting the directive display_errors
to true
(while having error_reporting
set to E_ALL
) prints all errors that occured during the current request bofore returing the PHP output.
Since I'm sending headers in my PHP code, I get several more errors (sending header after content has been sent is not possible).
Now I'd like to add the error messages to the end of my page. There I'd like to show all errors that occurred (until then). Unfortunately error_get_last only returns the last error that occurred.
I first thought that set_error_handler might solve the problem, but I'm afraid that my error-logging does not work anymore:
It is important to remember that the standard PHP error handler is completely bypassed for the error types specified by error_types unless the callback function returns FALSE.
Besides that:
The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.
But maybe they are also not available in error_get_last()
So is there a way to print all errors after the output of the generated content?
Referring to your first concern
The error handling will still work as long as the:
callback function returns FALSE
function myErrorHandler($error_level, $error_message, $error_file, $error_line, $error_context) {
// Do your stuff here, e.g. saving messages to an array
// Tell PHP to also run its error handler
return false;
}
One solution to store all error-numbers (in an outside array $error_list
) could be:
$error_list = array();
$myErrorHandler = function ($error_level, $error_message, $error_file, $error_line, $error_context) use (&$error_list) {
$error_list[] = $error_level;
// Tell PHP to also run its error handler
return false;
};
// Set your own error handler
$old_error_handler = set_error_handler($myErrorHandler);
Another approach is to use Exceptions. There is a nice example in the comments for the function set_error_handler()
Also see:
- Are global variables in PHP considered bad practice? If so, why?
- PHP: Callback function using variables calculated outside of it
Referring to your second concern:
As Egg
already mentioned: using register_shutdown_function()
is a way to go, and the code in the answer https://stackoverflow.com/a/7313887/771077 shows you how.
But keep in mind, that
- Registering the shutdown- and error-handling functions should be the first thing in code (I fool once had an error in a config file, which was not handled correct, since I registered the error handler afterwards).
- Parse errors might not be handled correctly (See comment in https://stackoverflow.com/a/7313887/771077)
There is a discussion about this here and here (amongst others), with the second answer on the latter list using a mix of set_error_handler()
with register_shutdown_function()
being a good solution.
Fuller example that catches all the errors (exceptions and errors), pumps to a log file and remembers in a static class; at the end you query the static class to get the error.
I use similar to this for all projects to get full control over all errors.
function customErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
ErrorHandler($errno, $errmsg, $filename, $linenum, $vars, true);
}
function nullErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
ErrorHandler($errno, $errmsg, $filename, $linenum, $vars, false);
}
function customExceptionHandler($exception) {
if (is_a($exception, 'exceptionError')) {
echo $exception->output();
} else {
ErrorHandler(E_ERROR, $exception->getMessage() . '(' . $exception->getCode() . ')', $exception->getFile(), $exception->getLine(), null, true);
}
}
function nullExceptionHandler($exception) {
if (is_subclass_of($exception, 'exceptionError')) {
$exception->output();
} else {
ErrorHandler(E_WARNING, $exception->getMessage() . '(' . $exception->getCode() . ')', $exception->getFile(), $exception->getLine(), null, false);
}
}
function ErrorHandler($errno, $errmsg, $filename, $linenum, $vars, $fatal) {
$errortype = array (
E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_DEPRECATED => 'Deprecated',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_USER_DEPRECATED => 'User Deprecated',
E_STRICT => 'Runtime Notice',
E_RECOVERABLE_ERROR => 'Catchable Fatal Error'
);
// Pushed into error log
if (error_reporting() > 0) {
$message = ': ' . $errmsg . ' in ' . $filename . ' on line ' . $linenum;
error_log('PHP ' . $errortype[$errno] . $message);
errorLogger::log($message);
if ($fatal) {
echo $errortype[$errno] . ': ' . $message;
exit();
}
}
}
class errorLogger {
private static $aErrors = array();
// ******************* Timing functions *********************************
public static function log($message) {
self::$aErrors[] = $message;
}
public static function getErrors() {
return self::$aErrors;
}
}
Usage Example
// Custom error handler. Can cope with the various call mechanisms
$old_error_handler = set_error_handler('nullErrorHandler');
$old_exception_handler = set_exception_handler('nullExceptionHandler');
// Do your stuff
// *
// *
// *
// *
// *
$old_error_handler = set_error_handler('customErrorHandler'); // Set to 'nullErrorHandler' to allow it to continue
$old_exception_handler = set_exception_handler('customExceptionHandler'); // Set to 'nullExceptionHandler' to allow it to continue
// At end
$errors = errorLogger::getErrors();
foreach($errors as $errorMessage) {
echo $errorMessage;
}
Catch the errors as you go and output messages at the end.
<?php
$errors = [];
try{
// code to test
} catch(\Exception $e) {
$errors[] = $e->getMessage;
}
try{
// next bit of code to test
} catch(\Exception $e) {
$errors[] = $e->getMessage;
}
...
// display all messages at the end
echo "\n<pre><code>\n";
print_r($errors);
echo "\n</code></pre>\n";
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
or
set your php.ini with this line:
display_errors=on