Converting PHP errors into exceptions - php

I've written error handling class which divided all errors into the normal ones (notices, warnings, ...), and the critical ones.
Now I've found out that it's a good practice to convert all errors into exceptions. It would also shorten my code.
However, I'm not sure how to handle this...
Are there exceptions that don't stop scripts execution, and exceptions that do? If there aren't...how to differ converted errors?
Converting errors into exception is done by calling set_error_handler() and throw new ErrorException() in there...What's next? set_exception_handler() is called automagically?

Caught exceptions do not stop your script, all uncaught ones do.
No, set_exception_handler() is not called automatically, you can do that if you like.
The exception handler you set with set_exception_handler() gets called after an exception has gone uncaught, it is the last piece of code that gets called before the script terminates. Make sure it doesn't cause an error/exception, or it will end badly.

Are there exceptions that don't stop scripts execution, and exceptions that do? If there aren't...how to differ converted errors?
Exceptions don't stop script execution if they're caught. To recognize a converted error:
try {
// ...
} catch (ErrorException $e) {
// converted error (probably)
} catch (Exception $e) {
// another kind of exception; this basically catches all
}
Or:
function handle_exception(Exception $e)
{
if ($e instanceof ErrorException) {
// converted error (probably)
} else {
// another kind of exception
}
}
set_exception_handler('handle_exception');
Note that ErrorException can be thrown by any piece of code, but it was meant to convert regular errors in set_error_handler() registered functions only.
Converting errors into exception is done by calling set_error_handler() and throw new ErrorException() in there...What's next? set_exception_handler() is called automagically?
If the thrown ErrorException from your error handler function is not caught anywhere else in your code, the registered exception handler (set using set_exception_handler()) will be called.

Any uncaught exception will stop execution of your script.
When an exception is thrown, code following the statement will not be
executed, and PHP will attempt to find the first matching catch block.
If an exception is not caught, a PHP Fatal Error will be issued with
an "Uncaught Exception ..." message, unless a handler has been defined
with set_exception_handler().
See docs about this
As for set_exception_handler() - it is not called automatically, but it is your last resort to react to the problem that occured
Sets the default exception handler if an exception is not caught
within a try/catch block. Execution will stop after the
exception_handler is called.

Keep in mind that you can only convert Warnings into Exceptions, errors cannot be converted to Exceptions because the error handler doesn't run.
set_error_handler(function ($severity, $message, $file, $line) {
echo 'You will never see this.'
});
// Provoke an error
function_that_does_not_exist();
It is possible to "catch" them using a shutdown function, but that is out of the scope of the question.

Related

PHP - Can't catch exception thrown by Google API lib

I want to catch an exception that is thrown by the Google API PHP library, but for some reason it generates a 'Fatal error: uncaught exception' before reaching my catch block.
In my app I have something like this:
try {
$google_client->authenticate($auth_code);
} catch (Exception $e) {
// do something
}
This is Google_Client's authenticate():
public function authenticate($code)
{
$this->authenticated = true;
return $this->getAuth()->authenticate($code);
}
The authenticate($code) above is Google_Auth_OAuth2::authenticate(), which at some point throws the exception:
throw new Google_Auth_Exception(
sprintf(
"Error fetching OAuth2 access token, message: '%s'",
$decodedResponse
),
$response->getResponseHttpCode()
);
If I put a try/catch block in the Google_Client's authenticate, it catches the exception, but without it the program just dies instead of reaching the main try/catch block from my app.
As far as I know this shouldn't be happening. Any ideas?
The problem was that the try/catch block was in a namespaced file and PHP requires you to use "\Exception". More info: PHP 5.3 namespace/exception gotcha
Example (taken from the link above):
<?php
namespace test;
class Foo {
public function test() {
try {
something_that_might_break();
} catch (\Exception $e) { // <<<<<<<<<<< You must use the backslash
// something
}
}
}
?>
I'm not sure how the structure of Google's API is, and I'm not a real fluent PHP programmer, but you're catching a specific exception type of Exception, with which Google's Google_Auth_Exception may not inherit from.
Therefore, since your try-catch block is looking for an exception that is a member of Exception and the Google_Auth_Exception is perhaps not a member of Exception, then your try catch block will miss it.
Try catching the specific exception. This has happened to me before in many different languages.
Edit
The link you posted inherits its exception from: Google/Auth/Exception
Google/Auth/Exception inherits its exception from: Google/Exception
Google/Exception extends Exception, which may, in this context be the Exception that your class is referring to.
It seems my justification for your try-catch block not catching an exception is completely wrong, but the wisdom could still be true. Try catching the specific exception, then use instanceof to see if PHP recognizes Google_Auth_Exception as a member of Exception.

Why does set_exception_handler(func) not catch exceptions?

An exception is thrown in my shutdown function and not caught within a try/catch block, for example:
<?php
set_exception_handler(function($e){
echo "exception handled"; // not echoed
});
register_shutdown_function(function(){
throw new Exception("test"); // this should be caught by the exception handler above, but it doesn't
});
Live run.
Running the above code gives:
Fatal error: Uncaught exception 'Exception' with message 'test'
However PHP Manual claims:
set_exception_handler sets the default exception handler if an exception is not caught within a try/catch block. Execution will stop after the exception_handler is called.
Why does exception_handler not catch the exception thrown?
Because it is beyond the scope...
http://www.php.net/manual/en/function.register-shutdown-function.php
Registers a callback to be executed after script execution finishes or exit() is called.
It must be stripping down your handlers as the execution of your script has finished and is in fact shutting down.

Using an Exception to Exit PHP Application

My app has a registered shutdown function and it seems there's some issues with that and my method of using an exception with a try/catch to exit the application (instead of using the exit() method due to FastCGI not liking this).
My problem is that if another exception is thrown in the try/catch block that isn't the ExitApp exception, it causes some unexpected results and the end result is the ExitApp exception isn't caught.
I'm seeing this on PHP 5.3.6, going to test it on another version now, but I'm curious if anyone can immediately point out what's wrong here.
<?php
// Define dummy exception class
class ExitApp extends Exception {}
try {
// Define shutdown function
function shutdown() {
echo "Shutting down...";
throw new ExitApp;
}
register_shutdown_function("shutdown");
// Throw exception!
throw new Exception("EXCEPTION!");
} catch(ExitApp $e) {
echo "Catching the exit exception!";
}
/**
* Expected Result: Uncaught Exception Error and then "Catching the exit exception!" is printed.
* Actual Result: Uncaught Exception Error for "Exception" and then Uncaught Exception Error for "ExitApp" even though it's being caught.
*/
You have wrong expectations from your code. Firstly, if you throw exception in your shutdown function, you will always end up with uncaught exception - shutdown functions are called outside tr/catch block.
Secondly you have no attempt to intercept unknown exception - you are only catching ExitApp types. you may want to try something like this:
try {
//some stuff
} catch(ExitApp $ea) {
//normal exit, nothing to do here
} catch(Exception $e){
//something rather unexpected, log it
}
Your shutdown() function is not even in a try/catch block, so it will never jump down to the catch for this exception type. It is going to run on exit so you will not longer be in that try/catch block.
On a more spiritual, try/catch is not meant for flow control. I'm not quite sure why you're trying to throw this to cause script exit, rather than just calling your own shutdown() method.
Hope that helps.

Throwing exception within exception handler

I have a script with an exception handler. This exception handler cleans up a couple connections, prior to the script exiting after an exception.
I would like to re-throw the exception from this exception handler so that it is handled by PHP's own last-resort exception handler, where the error is written to PHP's error log, or whatever the default is, as configured in PHP.ini.
Unfortunately, this doesn't seem like a possibility, as outlined here:
http://www.php.net/manual/en/function.set-exception-handler.php#68712
Will cause a Fatal error: Exception thrown without a stack frame
Is there another way to bubble the error up the stack so that PHP handles it after my exception handler is done cleaning up?
You can not re-throw from the exception handler, however, there are other places you can. For example you can de-couple the re-throw from the handler by encapsulating things into a class of it's own and then use the __destruct() function (PHP 5.3, Demo):
<?php
class ExceptionHandler
{
private $rethrow;
public function __construct()
{
set_exception_handler(array($this, 'handler'));
}
public function handler($exception)
{
echo "cleaning up.\n";
$this->rethrow = $exception;
}
public function __destruct()
{
if ($this->rethrow) throw $this->rethrow;
}
}
$handler = new ExceptionHandler;
throw new Exception();
Put this into my error log:
[29-Oct-2011 xx:32:25] PHP Fatal error: Uncaught exception 'Exception' in /.../test-exception.php:23
Stack trace:
#0 {main}
thrown in /.../test-exception.php on line 23
Just catch the exception and log the message yourself, then rethrow.
try {
$foo->doSomethingToCauseException();
} catch (Exception $e) {
error_log($e->getMessage());
throw $e;
}
If you bubble up to the top and PHP is unable to handle, it will result in uncaught exception.
Will cause a Fatal error: Exception thrown without a stack frame
This error means that your exception is thrown from a code that is not part of the script (as far as PHP knows). Examples of such code include custom exception handler set with set_exception_handler() and any class destructor method. There's no choice but to NOT throw an exception from such a code.
If you want PHP native error handling, I'd suggest you to call trigger_error() instead. It should log the error if you don't have custom error handler and you use suitable error type. For example, E_USER_ERROR should be fine.
Just rethrow the exception as a RunTimeException and it will keep the stacktrace :)
try {
// bad exception throwing code
} catch (Exception $e) {
throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
}
From http://www.php.net/manual/en/function.set-exception-handler.php#88082
i read:
Another solution is to restore the error handler at the beginning of the exception handler.
Have you tried it?

Is it possible in PHP to prevent "Fatal error: Call to undefined function"?

In PHP, is there any way that I can ignore functions that are undefined instead of throwing a fatal error that is visible in the browser?—i.e., Fatal error: Call to undefined function
I know that there is the practice of wrapping all custom functions in a conditional as below, but is there a programmatic way to get this effect?
if (function_exists('my_function')) {
// use my_function() here;
}
No. Fatal errors are fatal. Even if you were to write your own error handler or use the # error suppression operator, E_FATAL errors will still cause the script to halt execution.
The only way to handle this is to use function_exists() (and possibly is_callable() for good measure) as in your example above.
It's always a better idea to code defensively around a potential (probable?) error than it is to just let the error happen and deal with it later anyway.
EDIT - php7 has changed this behavior, and undefined functions/methods are catchable exceptions.
In php 7, this is now possible.
Example codez:
try {
some_undefined_function_or_method();
} catch (\Error $ex) { // Error is the base class for all internal PHP error exceptions.
var_dump($ex);
}
demo
http://php.net/manual/en/migration70.incompatible.php
Many fatal and recoverable fatal errors have been converted to exceptions in PHP 7. These error exceptions inherit from the Error class, which itself implements the Throwable interface (the new base interface all exceptions inherit).
What you are asking for seems a little goofy, but you can get a similar effect by declaring all your functions as methods of a class and then implement __call as a method of that class to handle any undefined method calls. You can then handle calls to undefined methods however you like. Check out the documentation here.
If you would like to suppress this error while working with objects use this function:
function OM($object, $method_to_run, $param){ //Object method
if(method_exists(get_class($object), $method_to_run)){
$object->$method_to_run($param);
}
}
Regards
we can hide errors but this will log in apache error log
//Set display error true.
ini_set('display_errors', "0");
//Report all error except notice
ini_set('error_reporting', E_ALL ^ E_NOTICE ^ E_STRICT);
//We can use try catch method
try {
my_method();
} catch (\Error $ex) { // Error is the base class for all internal PHP error exceptions.
var_dump($ex);
}
//Check method existance
function_exists()
Prevent no. But catch and log yes, using register_shutdown_function()
See PHP manual
function shutDown_handler()
{
$last_error = error_get_last();
//verify if shutwown is caused by an error
if (isset ($last_error['type']) && $last_error['type'] == E_ERROR)
{
/*
my activity for log or messaging
you can use info:
$last_error['type'], $last_error['message'],
$last_error['file'], $last_error['line']
see about on the manual PHP at error_get_last()
*/
}
}
register_shutdown_function ('shutDown_handler');
I found in PHP 7 that try/catch works for the "Call to undefined function" error. The Exception object that is caught is not of class Throwable and not ErrorException but Error.
The exception object received by catch contains the error message, the file and line nr, and stack trace, but does not contain the severity code.
This catch allows the program to do its own logging or analysis, and hides the error message from the user-visible output (but will log the error in the PHP error log), just what is wanted on production websites. It also allows execution to continue, which can be dangerous, but you can simply place "exit;" at the end of the catch code block to prevent the program from continuing.

Categories