I'm studying PHP right now and I'm using w3schools, but when I use the code below my page gets broken (stops from where the code is):
<?php
function myException($exception) {
echo "<b>Exception:</b> " . $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
?>
This code is for creating an exception when no catch block was found.
I tried the others examples in the page and everything works fine. I thought it may be happening because there is no try block, but I'm confused and I don't know how to use it in this situation.
Thanks in advance!
set_exception_handler documentation from php.net:
http://php.net/manual/en/function.set-exception-handler.php
Execution will stop after the exception_handler is called.
Actually the output you are getting is correct.
As stated in W3Schools documentation set_exception_handler() only sets a user-defined function to handle all uncaught exceptions (as in the example you quoted above). So the output should be something like this:
Exception: Uncaught Exception occurred
Please notice the form of exception is what you have defined in your function (myException); which means first it prints the word Exception: and then it prints the reason (message) of exception, in this case Uncaught Exception occurred.
EDIT
As mentioned in the comments the error handler causes the script to stop being executed. To avoid this situation is better always to handle exceptions using try catch blocks.
P.S: I'd suggest you to use better resources other than W3Schools (like the PHP documentations itself) if you are starting to learn PHP.
try this. Hope it helps. If not please let me know.
function myException($exception) {
try {
throw new Exception("Some error message");
} catch(Exception $e) {
echo $e->getMessage();
}
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
Related
I'm developing my own PHP framework and my code althought is working like it should, it's getting bigger and bigger; that of course leads to multiple ways for my framework to break, so I have decided it is time to implement Exception handling like any other PHP framework does, that 'nice' error view that tells you what might went wrong.
I have done my research and kind of understand how the Extension PHP default class works, I know that I'm able to extend this class and customize the error messages.
I also know that to trigger an Exception you gotta throw it and catch it with a "try/catch" statement, somethin like this...
class MyCustomException extends \Exception()
{
// My stuff
}
public function dontBeZero($number)
{
if ($number == 0) {
throw new MyCustomException('You gave me zero!!');
}
}
try {
dontBeZero(0);
} catch (MyCustomException $e) {
echo '<pre>';
$e->getMessage();
echo '</pre>';
}
I understand that, but my real question is: How does this popular frameworks such as Laravel, Symfony, etc manage to throw you a pretty message showing you what the error was, where do they keep all the logic that verifies whether it should or should not throw an exception, and most importantly where did they catch them?.
Most frameworks show these errors via a custom error handler. A popular one used by laravel is whoops.
You just need to register it as a custom handler, and you'll see the pretty error pages:
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();
Keep in mind, you should disable these on production (so that your stack traces/code isn't exposed).
See the two functions set_error_handler and set_exception_handler. These functions allow you to register a callback function which is called when an error or exception occurs.
These callback functions are called by the Php runtime and provided with error details as arguments. The error details include error line number, stack trace, file name and more. The callback function can then format and display this information
I'm not very smooth with PHP, because I'm only using it temporary. The nature of my code is very simple, and it does have a few cases where it comes to a "uncaught exception: exit".
How exactly can I use the exception handler to tell it restart the code when it gets this error?
See: http://php.net/manual/en/language.exceptions.php
Use try-catch statement:
try {
//your code here
} catch (Exception e) {
// do something if an exception is thrown.
}
PHP 5.5 is adding support for finally in try/catch blocks.
Java allows you to create a try/catch/finally block with no catch block, so you can cleanup locally when an exception happens, but let the exception itself propagate up the call stack so it can be dealt with separately.
try {
// Do something that might throw an exception here
} finally {
// Do cleanup and let the exception propagate
}
In current versions of PHP you can achieve something that can do cleanup on an exception and let it propagate, but if no exception is thrown then the cleanup code is never called.
try {
// Do something that might throw an exception here
} catch (Exception $e) {
// Do cleanup and rethrow
throw $e;
}
Will PHP 5.5 support the try/finally style? I have looked for information on this, but the closest I could find to an answer, from PHP.net, only implies that it doesn't.
In PHP 5.5 and later, a finally block may also be specified after the
catch blocks. Code within the finally block will always be executed
after the try and catch blocks, regardless of whether an exception has
been thrown, and before normal execution resumes.
The wording suggests that you're always expected to have a catch block, but it doesn't state it outright as far as I can see.
Yes, try/finally is supported (RFC, live code). The documentation is indeed not very clear and should be amended.
I've implemented a test case on a 5.5RC3 server.
As you can see in the code, it works as expected. Documentation is indeed wrong at this point.
Few days ago I deal with errors like this...
exit( 'Error!' );
or exit( 'Error!' );
Doh, right? =] Now I'm trying to learn Exceptions. This is how far I got...
http://pastie.org/1555970
Is that correct use of them? It would be cool that I can have more info about 'em. Like file where exception is thrown and line of that file. I know that there are build-in methods (in Exception class), but I want to somehow extend it so I don't need to write...
throw new My_Exception( '...' );
catch( My_Exception $e ) {
echo $e->my_method();
}
...but use old syntax.
throw new Exception( '...' );
catch( Exception $e ) {
echo $e->getMessage();
}
...or maybe you have any greater thought of Exceptions? How to deal with them? Help me! =]
In general you only need to echo/log exceptions, that cannot be otherwise handled. This pretty much means, that if you put your entire application within try block, there's only one place where you need to put echoing/logging logic (i.e. the catch block associated with the outermost try block).
If on the other hand the exception can be handled without stopping the application (in your example this could be providing a default numeric value, instead of incorrect value), then there's usually no need to echo/log it.
If you do want to log such exceptions (for debugging for example), then your application should contain a logging framework, so that it's enough to do in your catch blocks something like
} catch (Exception $e) {
ExceptionLogger::log($e); //static method == ugly, but it's for simplicity in this example
// do whatever needs to be done
}
log() method above would check if the logging is enabled, and if it is savenecessary data to a file.
Exceptions should be typed based upon the error that you find. The Spl Exceptions are a good start, but you really should be creating your own exceptions as well. Some common ones that I use:
FileNotFoundException extends RuntimeException <- self explanatory
HTTPException extends RuntimeException <- Used for http classes when a non-200 result is encountered
DatabaseQueryException extends LogicException <- Used for database query errors
Now, by typing them specifically, it lets you handle the errors in your code. So let's say that you want to fetch a HTTP resource. If that fails with anything but a 404, you want to try a backup URL. You could do that with:
try {
return getHttp($url1):
} catch (HttpException $e) {
if ($e->getCode() != 404) {
try {
return getHttp($url2);
} catch (HttpException $e2) {
//It's ok to ignore this, since why know it's an HTTP error and not something worse
return false;
}
} else {
return false;
}
}
As far as your example code that you posted, I would change a few things:
Change the thrown exception to InvalidArgumentException since it has more semantic meaning (I almost never throw a raw exception).
You should try to avoid catch(Exception $e) at all costs. You have no idea what exception was thrown, so how can you possibly handle it?
Only catch exceptions that you are reasonably sure you know how to handle (and outputting an error/logging is not handling, it's removing the usefulness of the exception). You should never see something like catch($e) { logerror($e); } or catch($e) { print $e->getMessage(); } since netiher is actually handling the exception.
If you don't fix or workaround the cause of the exception in your catch block, you should re-throw it. Let the code above you in the stack try to handle it. This is especially true with libraries and classes that are reused all over the place.
Now, with user interfaces, it may be acceptable to catch the exception and show the user an error message. So your example where you print the exception's message might be ok, but you'd really need to think about the use-cases of it. Are you calling it from a model or controller? If so, it may be ok display an error message. Are you calling it from a library? If so, it's probably better to let the exception bubble up.
Also, don't use a global try{} catch() {} block. Instead, install an Exception Handler to handle it for you. It's cleaner, and more semantically correct (since any try{}catch{} implies that you know how to handle the exception that you caught, whereas the exception handler is precisely meant for exceptions that weren't handled because you didn't know how to handle them.
Exceptions are for exceptional circumstances. Do not use them for all error conditions. If a user submits a password that's too short, don't throw an exception, handle that in validation. But if your hash function is expecting sha256 to be available and it isn't, that's a time for an exception. Exceptions are useful for program errors (when a condition that is unexpected happens, such as invalid input to a function), state errors (when the application enters a state that is unknown or unstable, such as if the requested view does not exist) and runtime errors (when the application encounters an error that can only be detected at runtime, such as a file-not-found error).
There is an entire page of the PHP manual devoted to extending exceptions and that page also gives you a lot of information on the methods to identify file/line number, backtrace etc. where the exception was thrown. This is the type of information that is extremely useful for debugging.
catch is not working because there is installed an exception handler using set_exception_handler()
I need "catch" to work, so I guess I need to unset the exception handler somehow. Things such as set_exception_handler(NULL) isn't working.
Any ideas how to unset the exception handler?
function my_exception_handler($exception) {
error_log("caught exception: " . $exception->getMessage() );
}
set_exception_handler("my_exception_handler");
// QUESTION: how does on unset it ?
//set_exception_handler(NULL);
try {
throw new Exception('hello world');
error_log("should not happen");
} catch(Exception $e) {
error_log("should happen: " . $e->getMessage());
}
Actual output:
caught exception: hello world
Desired output:
should happen: hello world
restore_exception_handler, which is linked from the manual entry for set_exception_handler.
BTW, these exception handlers should only come into play when an exception is uncaught. A catch block should always have precedence.
Reading a little bit in the comments on the Exceptions page brings you to this bug and this bug. They describe exactly what you experience, Exceptions can't be caught when a custom error handler is defined.
Solution:
Fixed in 5.3 and HEAD, won't be backported to 5.2.
The function is restore_exception_handler. However, the handler should only be called when an exception is unhandled. It does not disable catches.