In the controllers class files, most of the method functions include try/catch block something like this:
try
{
$stmt = $this->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
//foreach() or so on...
}
catch (Exception $e)
{
//bunch of code...
//save error into database, etc.
//error into json and pass to view file
}
There are a lot of code in the catch block, is there a way to reduce it. Is possible to add "throw exception" in the catch block?
Yes, it is. Try it by yourself. You can always throw a new Exception in a catch block or rethrow the same exception.
try
{
// ...
}
catch (Exception $e)
{
// do whatever you want
throw new Your_Exception($e->getMessage());
// or
throw $e;
}
I don't know what "bunch of code" is. I'm not sure I believe you. If you have that much going on in a catch block you're doing something wrong.
I'd put this kind of code into an aspect if you have AOP available to you.
"Error into database" might throw its own exception. What happens to that?
The only step that I see here that's necessary is routing to the error view.
What does rethrowing the exception do? It's just passing the buck somewhere else. If all these steps don't need to be done, and all you're doing to rethrowing, then don't catch it at all. Let the exception bubble up to where it's truly handled.
You shouldn't be catching Exception. That's much too general. Catch each specific type of Exception with multiple catch statements on your try block:
try {
} catch(PDOException $err) {
} catch(DomainException $err) {
}
Related
I perfectly understand the nuances of the (try/throw/catch) block.
What I don't understand is:
If we gonna use an IF (or any control structure) inside our try block anyway in order to test if a condition is met, only then, 'throw' an exception if the results of that test is false, then... in my opinion: throw/generate an exception is useles; because if a condition is not met, we can simply print an error message, call a function, instantiate a class, redirect to another location, etc.
Another story would be, if for instance, a variable was not initialized, we enclose that variable inside a try{} block, echo the variable, and from that point onward, everything will be handle by the catch() block because the try block raises an error; and since the try/catch blocks talk each other, the catch block will catch every error that was originated from his corresponding try block. However, you can set a custom error message inside yout try block (optional).
What I've read so far:
every results from searching: if vs. try
I do see the difference.
But I can not understand why some people choose try/throw/catch over if...else...switch...while... etc.
As far I can see, try/throw/catch can be used for debugging, though.
One benefit of exceptions over if/then is that you can wrap try/catch around a large block of code. It will be triggered if an error happens anywhere in the block.
try {
$db = db_open();
$statement = $db->prepare($sql);
$result = $statement->execute($params);
} catch (Exception $e) {
die($e->getMessage());
}
With if/then, you would have to perform a test at each step.
$db = db_open();
if (!$db) {
die(db_connect_error());
}
$statement = $db->prepare($sql);
if (!$statement) {
die(db_error($db));
}
$result = $statement->execute($params);
if (!$result) {
die(db_error($db));
}
As you said, it's a lot of overhead to throw an exception inside a try/catch block and catch it immediately.
try {
if (...) {
// good, do no throw
} else {
throw new Exception();
}
} catch ($e) {
// handle exception
}
This should be replaced by:
if (...) {
// good
} else {
// handle error, no exception
}
Exceptions are useful because they bubble up. So imagine if you have this code instead:
function bla() {
try {
tryToDoSomething();
} catch ($e) {
// handle error
}
}
function tryToDoSomething() {
if ($somethingNotAvailable) {
throw new Exception();
}
doSomething();
}
In this case, the function that defines the try/catch is NOT the one throwing the exception. tryToDoSomething() does not know how to handle the errors so it will let parent methods to take care of it. The exception can bubble up the call stack until someone catches it and handles the error. That's how exceptions can actually be useful :)
I have a problem where I want to catch all exception except descendants of my custom exception.
Maybe bad design, but here it is (Simplified and names changed, but the code is quite accurate):
function doStuff()
{
try {
// code
if (something) {
// manually throw an exception
throw StuffError("Something is bad.");
}
// a third-party code, can throw exceptions
LibraryClass::arcaneMagic();
} catch (Exception $e) {
throw new StuffError("Error occured while doing stuff: "
. $e->getMessage());
}
}
/** My custom exception */
class StuffError extends Exception
{
function __construct($msg) {
parent::__construct('StuffError: ' . $msg);
}
}
However, the issue here is that I don't want the try-catch to intercept the manually throws StuffError. Or, seamlessly rethrow it or something.
As it is now, I'd get:
StuffError: Error occured while doing stuff: StuffError: Something is bad.
I want just:
StuffError: Something is bad.
How would I do it?
You can have multiple catch clauses, and the first one that matches will be the one that runs. So you could have something like this:
try {
do_some_stuff();
}
catch (StuffError $e) {
throw $e;
}
catch (Exception $e) {
throw new StuffError(Error occurred while doing stuff: " . $e->getMessage());
}
But you might want to rethink wrapping stuff like this. It obscures the real cause of the error. For one thing, you lose the stack trace. But it also complicates error handling, since now someone can't differentiate exception types the way you're trying to do, short of trying to parse the exception message (which is rather an anti-pattern in itself).
I might be misinterpreting you, but I think this is what you're looking for:
...
} catch (Exception $e) {
if (get_class($e) == 'StuffError' || is_subclass_of($e, 'StuffError')) {
throw $e;
} else {
throw new StuffError("Error occured while doing stuff: "
. $e->getMessage());
}
}
...
Replace your catch statement with the code above. It checks to see if the exception is a StuffError or a child class of StuffError. I'm still very confused at why you would need to throw a StuffError exception after you catch, but maybe that's just some weirdness coming from translating/cleaning your code.
I have a situation where I would like to re-throw an exception inside a catch block and have it caught by a more generic catch.
Example:
try {
somethingThatMightThrowExceptions();
}
catch (ClientErrorResponseException $e) {
if ($e->getResponse()->getStatusCode() == 404) {
return $this->notFound();
}
throw $e; // even tried throw new \Exception();
}
catch (\Exception $e) {
return $this->serverError('Server error');
}
So in my first catch block I check for a specific condition, and if that fails I would like to re-throw the exception and have it caught by the generic catch (\Exception) block. But in this case it just bubbles back up to the caller.
The problem is that there are actually a couple more lines of code in the final catch, which I don't want to repeat. I could of course extract them to a method, but that feels like overkill.
So basically I want to do it all in-line without having to add extra layers. Any suggestions?
It's due to catch only working once as you are throwing an exception not withing a try block.
If you are determined, that you want to do it this way, then you need to nest try..catch statements as #deceze suggested in comments..
You should describe what you are trying to accomplish instead, as there might be a better way to do it.
You have two options:
a) Extract common logic to a method. (This can be overkill sometimes as you've mentioned)
b) Catch the most generic exception and check for its type. ie:
try{
somethingThatMightThrowExceptions();
}
catch (\Exception $e) { // The most generic exception
if($e instanceof ClientErrorResponseException) {
// Some actions specific to ClientErrorResponseException
}
// Shared actions
}
You have two options:
a) Catch the most generic exception and check for its type, as #deceze suggested
try{
somethingThatMightThrowExceptions();
}
catch (\Exception $e) { // The most generic exception
if($e instanceof ClientErrorResponseException) {
// Some actions specific to ClientErrorResponseException
}
// Shared actions
}
b) Put anoter try/catch block at upper level
try {
try {
somethingThatMightThrowExceptions();
}
catch (ClientErrorResponseException $e) {
// Some actions specific to ClientErrorResponseException
throw $e ;
}
}
catch (\Exception $e) { // The most generic exception
// Shared actions
}
This question is about the best way to execute code outside of try block only if no exception is thrown.
try {
//experiment
//can't put code after experiment because I don't want a possible exception from this code to be caught by the following catch. It needs to bubble.
} catch(Exception $explosion) {
//contain the blast
} finally {
//cleanup
//this is not the answer since it executes even if an exception occured
//finally will be available in php 5.5
} else {
//code to be executed only if no exception was thrown
//but no try ... else block exists in php
}
This is method suggested by #webbiedave in response to the question php try .. else. I find it unsatisfactory because of the use of the extra $caught variable.
$caught = false;
try {
// something
} catch (Exception $e) {
$caught = true;
}
if (!$caught) {
}
So what is a better (or the best) way to accomplish this without the need for an extra variable?
One possibility is to put the try block in a method, and return false if an exception is cought.
function myFunction() {
try {
// Code that throws an exception
} catch(Exception $e) {
return false;
}
return true;
}
Have your catch block exit the function or (re)throw/throw an exception. You can filter your exceptions as well. So if your other code also throws an exception you can catch that and (re)throw it. Remember that:
Execution continues if no exception is caught.
If an exception happens and is caught and not (re)throw or a new one throw.
You don't exit your function from the catch block.
It's always a good idea to (re)throw any exception that you don't handle.
We should always be explicit in our exception handling. Meaning if you catch exceptions check the error that we can handle anything else should be (re)throw(n)
The way I would handle your situation would be to (re)throw the exception from the second statement.
try {
$this->throwExceptionA();
$this->throwExceptionB();
} catch (Exception $e) {
if($e->getMessage() == "ExceptionA Message") {
//Do handle code
} elseif($e->getMessage() == "ExceptionB Message") {
//Do other clean-up
throw $e;
} else {
//We should always do this or we will create bugs that elude us because
//we are catching exception that we are not handling
throw $e;
}
}
I am nesting try catches inside of a main try catch statement, what I would like to know is how I can make the main try catch fail if one of the nested try catches fails?
Here is my code:
try
{
try
{
//how can I make the main try catch fail if this try catch fails?
}
catch(Exception $e)
{
error_log();
}
}
catch(Exception $e)
{
error_log();
}
After error_log(); in the first try-catch, type throw $e; (on a new line). This will throw the error again, and the outer try-catch will handle it.
You should extend Exception for the various different types of Exception. That way you can trigger a specific try-catch block:
try
{
...
try
{
throwSomeException();
}
catch ( InnerException $e )
{
...do stuff only for InnerException...
}
...
}
catch ( Exception $e )
{
...do stuff for all types of exception...
}
Additionally, you can chain your catch statements to trigger different blocks in a single try-catch:
try
{
...
}
catch ( SpecificTypeOfException $e )
{
..do something specific
}
catch ( TypeOfException $e )
{
..do something less specific
}
catch ( Exception $e )
{
..do something for all exceptions
}
Inside the inner catch, throw() - NOT recommended, I've seen several issues with PHP when doing this. Or set a flag to throw just after the inner catch.
Here's an example throwing the same exception (or you could throw a different one).
try {
$ex = null;
try {
//how can I make the main try catch fail if this try catch fails?
} catch(Exception $e){
$ex = $e;
error_log();
}
if ($ex) {
throw $ex;
}
} catch(Exception $e){
error_log();
}
I handle exceptions in a way similar to eventHandling in Javascript.
An event bubbles up the ladder from specific to generic. When it reaches the start program, an exception lost all it's meaning to the code and should simply be caught for logging and ending an application.
In the meantime a lot of stuff can happen
CallStack:
Start Lunch
Eat Apple (Before this code, an apple was bought as lunch)
Sink teeth in apple
During my eating of the apple, a worm appeared:
throw NausiaException('I found a bleeding worm...');
Eat Apple scope catches
catch(Exception $e)
the exception because in that scope we can return the apple to the store and shout at the manager. Since nothing more useful can be said about the occurrence,
throw $e
is called because eating the apple failed.
Something could've gone different
However, if the store manager refused to refund, you can wrap the exception
throw new RefundFailedException('The manager is a cheap skate', RefundFailedException::REFUSED, $e)
Start lunch Scope
Start lunch scope wants to throw away bad lunch
try {
//Start lunch
} catch (Exception $e) {
switch (true) {
case $e instanceof NausiaException:
case $e instanceof RefundFailedException:
//Throw lunch away
break;
}
}
use of a bool variable and "return" keyword at appropriate place could do the trick for you...