I have the following code:
do {
try {
$result = $class->function_x($params); //this will fire an Exception
break;
}
catch (Exception $e)
{
error_log($e->getMessage());
sleep(5);
}
} while(true);
Is this an endless loop?
The method call fire an Exception so the catch write to error_log and wait for 5 seconds, but because of the Exception the break is not executed (to break the while) and the loop will be endless.
Is that correct or I am missing something?
If $result = $class->function_x($params); throws Exception it will never go to break;, because it will jump out to catch just after an Exception.
So yes, it looks like endless loop.
Yes, if $class->function_x($params); always throws exception, then it is endless loop.
As soon as the exception thrown, the control is given into catch block and break will never be executed.
You should not use break statement inside a try catch. You can use goto for this task. This will prevent your exceptions :
do {
try {
$result = $class->function_x($params);
if(something) goto bre;
} catch(Exception $e) {
error_log($e->getMessage());
sleep(5);
}
bre:
} while(true);
Related
In the following over simplified scenario, I'm wondering if firstFunction() fails, will secondFunction() still run but then show the error, or will it break out of the try block when firstFunction fails?
try {
firstFunction();
secondfunction();
} catch (\Exception $e) {
echo $e...
}
Is it possible to catch an exception in an generator and just yield the next value? I tried something similar like the code in the example below, but it stops on an exception and does not yield the next value as "expected".
function generator(){
foreach($aLotOfWork as $task){
try {
$promise = doSomethingThatCanFailBadly($task);
yield $promise;
} catch (Exception $e) {
echo "oh.. there is an error, but I don't care and continue";
}
}
}
IMHO This is not a duplicate of (php: catch exception and continue execution, is it possible?), because this person just wanted to know how to catch an exception in php and go on. In my case I already catch all exceptions, but the generator stops and does not go on as intended.
Your code is right and it will capture the exception and continue, check this out:
$ cat so.php
<?php
function doSomethingThatCanFailBadly($task) {
if ($task == 3) {
throw new Exception();
}
return $task;
}
function generator(){
$aLotOfWork = array(1,2,3,4,5);
foreach($aLotOfWork as $task){
try {
$promise = doSomethingThatCanFailBadly($task);
yield $promise;
} catch (Exception $e) {
echo "oh.. there is an error, but I don't care and continue\n";
}
}
}
foreach (generator() as $number) {
echo "$number\n";
}
?>
$ php so.php
1
2
oh.. there is an error, but I don't care and continue
4
5
Have a look at your error stack trace. Maybe what's happening is that something inside your doSomethingThatCanFailBadly method is producing an exception but it is also catching it and forcing the quit with die() or exit() before it ever gets to your catch block. There's not much you can do in that case. You could maybe use register_shutdown_function and see if that helps, but that is starting too look messy.
You would need to save to output of the generator to an array, and if during individual yields an exception is thrown, with right exception handling, it simply will not get into the array.
In your example the doSomethingThatCanFailBadly throws an exception, then the program flow gets to the catch branch. So actually doSomethingThatCanFailBadly has no return value that could be assigned to $promise - so there's nothing to yield at that point.
#palako explained the problem very nicely, but he does not really provide a solution for my case. I use this generator to generate Promises and the consumer (Guzzle's EachPromise-method) seems to stop working on an Exception. So I replaced the throw new SomeException('error message') statement by return RejectedPromise('error message').
I have to admit that this is a very situation-specific solution, but you can do something similar in other settings too: just return an object instead of using exceptions.
I wonder if it's posible to get all the exceptions throwed.
public function test()
{
$arrayExceptions = array();
try {
throw new Exception('Division by zero.');
throw new Exception('This will never get throwed');
}
catch (Exception $e)
{
$arrayExceptions[] = $e;
}
}
I have a huge try catch block but i want to know all the errors, not only the first throwed. Is this possible with maybe more than one try or something like that or i am doing it wrong?
Thank you
You wrote it yourself: "This will never get throwed" [sic].
Because the exception will never get thrown, you cannot catch it. There only is one exception because after one exception is thrown, the whole block is abandoned and no further code in it is executed. Hence no second exception.
Maybe this was what the OP was actually asking for. If the function is not atomic and allows for some level of fault tolerance, then you can know all the errors that occurred afterwards instead of die()ing if you do something like this:
public function test()
{
$arrayExceptions = array();
try {
//action 1 throws an exception, as simulated below
throw new Exception('Division by zero.');
}
catch (Exception $e)
{
//handle action 1 's error using a default or fallback value
$arrayExceptions[] = $e;
}
try {
//action 2 throws another exception, as simulated below
throw new Exception('Value is not 42!');
}
catch (Exception $e)
{
//handle action 2 's error using a default or fallback value
$arrayExceptions[] = $e;
}
echo 'Task ended. Errors: '; // all the occurred exceptions are in the array
(count($arrayExceptions)!=0) ? print_r($arrayExceptions) : echo 'no error.';
}
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...