I've trying to use this:
$error_handler = function($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
};
$exception_handler = function($exception) {
self::invokeHttpError(500);
};
set_error_handler($error_handler, E_ALL | E_STRICT);
set_exception_handler($exception_handler);
However, it fails when I call this:
$fn = function() {
$application->test(); // $application is undefined
};
$fn();
The error handler is called, but not the exception handler. What is happening?
Dereferencing an undefined object results in a fatal and uncatchable error. That's why your exception handler and error handler are not called when this happens.
This behaviour really irritates me as a developer though, I wish it would get turned into a catchable exception instead.
Update
One thing you could do to curb this problem is to throw an ErrorException inside your regular error handler. This would prevent an uncatchable fatal error when dereferencing an undefined symbol.
Related
What happens with set_error_handler() on PHP7 now that all errors are exceptions? makes me think that recoverable errors can be caught but that does not appear to be the case, as demonstrated here:
<?php
$_SERVER['TEST'] = new stdClass;
try {
phpinfo();
} catch (\Throwable $e) {}
If you run that code you'll get this as the output:
$_SERVER['argc'] => 1
$_SERVER['TEST'] =>
Recoverable fatal error: Object of class stdClass could not be converted to string in /Users/username/zzz.php on line 6
So clearly an error is being "issued" but one is not being thrown, unless I'm misunderstanding something?
Not all errors were converted to Throwable errors in PHP 7.
Actually, the docs say:
most errors are now reported by throwing Error exceptions.
(Emphasis mine). Most !== All.
Some errors are still not catchable.
Funnily enough, the error message used you get used to say "Catchable Fatal Error" instead of "Recoverable Fatal Error" before PHP 7.1 was released.
This was reported as a bug, but the solution implemented by the devs was change the error string from Catchable to Recoverable to dispel misconceptions.
In the specific case you are testing, it seems that phpinfo() raises a recoverable error instead of throwing an Error, so it makes sense you can't catch it this way.
Still, not all hope is lost.
What you could do is convert all errors to exceptions by implementing your own error handler. An example of this is described on the ErrorException documentation:
function exception_error_handler($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting
return;
}
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler("exception_error_handler");
The neat thing of this example is that it takes into account your error reporting settings, so only errors that would have been reported under your settings are actually thrown as exceptions. Otherwise, nothing happens.
Testing your code:
<?php
function exception_error_handler($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting
return;
}
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler("exception_error_handler");
$_SERVER['TEST'] = new stdClass;
try {
phpinfo(INFO_VARIABLES);
} catch (\Throwable $e) {echo 'CAUGHT!!!!!!';}
prints the following output:
$_SERVER['TERM_SESSION_ID'] => w0t1p0:xxx-cxx-xxxxxxx-xxxxx
$_SERVER['SSH_AUTH_SOCK'] => /private/tmp/com.apple.launchd.xxxxxxxx/Listeners
$_SERVER['LC_TERMINAL_VERSION'] => 3.3.2
....
$_SERVER['argc'] => 1
$_SERVER['TEST'] =>
CAUGHT!!!!!!%
This has bugged me for some time.
When I call set_error_handler(), errors and warnings and notices are routed to my handler, and when i call restore_error_handler(), my previously defined handler is restored. But what happens when an exception is thrown before restore_error_handler() is called?
I have the following defined within a class:
function do_something() {
set_error_handler([$this, 'convert_errors_to_exceptions']);
//stuff that may trigger error, e.g.
trigger_error('testing an error');
//will this actually ever be called?
restore_error_handler();
}
public function convert_errors_to_exceptions($num, $message, $file, $line) {
//if error reporting turned off
if (!(error_reporting() & $num)) return false;
//convert to exception - then what happens?
throw new Exception("Error: $message in $file on line $line");
return true;
}
Will restore_error_handler() ever be called if an error is triggered? And do I have to call restore_error_handler() immediately prior to throwing the exception if I want my previous handler to actually handle the exception itself?
Cart/horse problems!
Is it possible to capture/gather all the errors on page and concatenate them to a string by using:
$allErrors = "";
$allErrors .= error_get_last(); // Each time an error shows up
I like to log errors in my database and would prefer to log all these PHP errors since I already have SQL-related PHP Fatal Errors logged.
error_get_last(), like the name is suggesting, only gives you the last error. And the fact that most errors will stop your script from running will get you only the last one and none of the previous ones. But you can set an own handler to catch every thrown error and exception. Here is an example
//function for exception handling
function handle_exception (Exception $exception) {
//here you can save the exception to your database
}
//function for error handling
function handle_error ($number, $message, $file, $line, $context = null) {
//pass/throw error to handle_exception
throw new ErrorException ($message, 0, $number, $file, $line);
}
//set error-handler but only for E_USER_ERROR and E_RECOVERABLE_ERROR
set_error_handler ('handle_error', E_USER_ERROR|E_RECOVERABLE_ERROR);
//exception-handler
set_exception_handler ('handle_exception');
I want to receive the error message in php before it gets executed. Basicly what i mean is that if I would have a bad code:
// This code is incorrect, I want to receive the error before it gets handled!
$some_var = new this_class_is_not_made;
Now that class does not exist, so it would be handles by the default error handler in php. But I want to disable the normal error handler and create my own.
Another example:
somefunction( string some_var ); // some_var misses the variable prefix. ( $ )
Example error message:
Fatal error: function 'some_var' is not defined in line: $x!
And this error would be: somefunction( string some_var );
But how would I receive the messages but also disable the normal error system?
EDIT: Making the error system execute a user-defined function
// I would want the error system to execute a function like this:
function(string $errorMessage, int $error_code){
if($error_code < 253){ return "Fatal error"; }
if($error_code < 528 && $error_code > 253){ return "Warning"; }
}
Answer found: By: ShiraNai7
try
{
// Code that may throw an Exception or Error.
}
catch (Throwable $t)
{
// Executed only in PHP 7, will not match in PHP 5
}
catch (Exception $e)
{
// Executed only in PHP 5, will not be reached in PHP 7
}
In PHP 7.0.0 or newer the code will throw Error exception if this_class_is_not_made doesn't exist.
try {
$some_var = new this_class_is_not_made;
} catch (Error $e) {
echo $e->getMessage();
}
Note that that this will also catch any other Error exceptions in case this_class_is_not_made does exist and causes some other error along the way.
In PHP versions prior to 7.0.0 you're out of luck - fatal errors always terminate the main script.
It might be a better idea to use class_exists() instead:
if (class_exists('this_class_is_not_made')) {
$some_var = new this_class_is_not_made;
}
This works in all PHP versions that support classes.
I have the following code to setup my error/exception handlers:
// Set the exception handler
set_exception_handler(function($e) {
echo 'Exception';
});
// Set the error handler
set_error_handler(function($code, $message, $file, $line) {
throw new ErrorException($message, 0, $code, $file, $line);
});
I have read numerous articles which have said to throw an exception within the set_error_handler callback function. This should mean I only have to handle exceptions. However the set_exception_handler callback function is never called and instead I get the warning:
Warning: Uncaught exception 'ErrorException' with message...
Please note that I am using PHP 5.4.
I tried to run the PHP script below, and it runs fine.
// set the exception handler
set_exception_handler(function($e) {
echo ' Exception';
});
// set the error handler
set_error_handler(function($code, $message, $file, $line) {
echo " Error [$message]";
throw new ErrorException($message, 0, $code, $file, $line);
},-1);
// trigger error
trigger_error('My own error.',E_USER_ERROR);
It returns:
Error [My own error.] Exception
Its exactly the same as yours. I cannot find anything wrong with the piece of code you provided, could the problem be outside it?