Returning from an Exception - php

This is probably going to sound like a sci-fi request, though – is there a way to return to the beginning of the try {} block where Exception was thrown from within the catch() {} block?
Here is an example:
try
{
// make OAuth request
}
catch(OAuthException $e)
{
// if(){}
// If tells me that the Exception was thrown because the access token is expired
// I have alternative access token (that's always up to date, but there is a catch why I void using it)
// I set it as a new access token and want to repeat the try {} block
}
Obviously goto could do it, though, I am looking if there is a more sophisticated approach.

You can wrap the code up inside a function and call the same function from the catch section
function remotePost($accessToken){
try{
}catch(OAuthException $e){
//the one used is not alternative token and if there is an alternative access token
return remotePost($alternativeAccessToken);
}
}

A while loop.
do {
$ok = false;
try {
// something
$ok = true;
} catch (...) {
// something
}
} while (!$ok);
AksharRoop's and Broncha's solution is also nice, especially if you have a limited number of backup plans (i.e. for the specific scenario you describe). Using while is somewhat more general.

Move your try block to a separate function so that you can call it again with a new token.
try
{
MakeAuthRequest(token);
}
catch(OAuthException $e)
{
if (failedDueToToken)
{
MakeAuthRequest(newToken);
}
}

Related

When it comes to handle errors, in what sense, using Exceptions are better that utilize if...else...switch... etc.?

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 :)

Cleanest way to execute code outside of try block only if no exception is thrown

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;
}
}

PHP exceptions in foreach loop

Which is the right way to implement php exception (try{}catch(){}) in a foreach loop that looks like this:
foreach ($apis as $api)
{
$api = '_'.$api;
$searchResults[$api] = $this->$api($parameters);
}
I want to implement the php exceptions for if one of the $this->api(); returns an error message, than catch it and do a if inside the catch to display the right message for the error message returned.
Edit:
Also, when capturing the error and if the error message is 1 (for example) is it a good way to do:
$searchResults['api'] = $this->_api($parameters);
so it tries to do the function again and see if this time it brings valid data?
foreach ($apis as $api)
{
$api = '_'.$api;
try {
$searchResults[$api] = $this->$api($parameters);
}
catch(ParameterException $e) {
// parameterexception handling here
echo "A ParameterException was thrown";
}
catch(Exception $e) {
// All other exceptions
echo "Some other Exception was thrown";
}
}
You can differentiate between more Exception-Types as well.
Since the catch block will be executed only in case of an exception, it really makes no difference if you wrap the for-each loop inside the try block, or if you put the try-catch inside the loop's body.
You should take whatever adds more clarity. However, doing it inside the loop will enable you to handle more specific exceptions relevant to the loop's body if the need arises in the future.
Also, since exceptions are typed, you don't need to do an if, just put different catch clauses:
try {
:
} catch (FirstExceptionType $e) {
:
} catch (SecondExceptionType $e) {
:
}
The code you use will always fail, because you are trying to use a variable ($this->$api($params);) as a function. How ever, you could implement your try-catch as follows:
foreach ($apis as $api)
{
$api = '_'.$api;
try {
$searchResults[$api] = $this->$api($parameters);
}
catch(Exception $e) {
// handle exception
}
}
You can also handle multiple Exceptions of different types by adding another catch() with another Exception class inside it, like:
foreach ($apis as $api)
{
$api = '_'.$api;
try {
$searchResults[$api] = $this->$api($parameters);
}
catch(OtherException $e) {
// Handle it
}
catch(Exception $e) {
// Handle it
}
}

Php for loop with try catch

This question is in continuation from this as suggested by one of the user.
I am using the getIDs function as below to process the id's. CheckValid() will check if the id's is a valid one to be processed, if yes then it will go to the next one updateUsers(). Check valid just checks for a condition and if not it throws an exception. updateUsers() just updates a column if it passes checkValid().
Problem – If I get 4 id's as output from getIDs(), and with the execute(), it process 2 for example and if it fails for 2nd id, it doesn't continue for the rest 2 id's ..I want it to continue so I commented out the "throw $e in the catch block".
Function execute() {
for($i=0 ; $i<count($this->getIDs()); $i++) {
try {
$this->checkValid();
$this->updateUsers();
} catch(Exception $e) {
//throw $e;
}
have you try a simple continue in the catch block ? didn't test but maybe something like that:
Function execute() {
for($i=0 ; $i<count($this->getIDs()); $i++) {
try {
$this->checkValid();
$this->updateUsers();
} catch(Exception $e) {
//throw $e;
continue; // if not working try a continue 2;
}
}
}
It sounds like you're using exceptions as booleans, I'd suggest avoiding that, as it gets confusing quickly, unless you really need the contents of the exception. See if this makes any sense for your use case (I'll grant, it may not).
// returns true if valid, false otherwise
function checkValid(){
try {
// do your validation
return true;
} catch (Exception $e) {
// optional: save the exception in case we want to know about it
$this->last_error = $e;
return false;
}
}
function execute() {
for($i=0 ; $i<count($this->getIDs()); $i++) {
if($this->checkValid()){
$this->updateUsers();
}
// if you want to do something with an error, simply add an else clause
// and handle $this->last_error
}
}
Also, I obviously don't know your code or what exactly you're doing, but looping n times and calling checkValid() and updateUsers() without parameters seems like very poor practice. Much better to, for instance, loop over the list of IDs and check each ID and user in turn, something like this:
foreach($this->getIDs() as $id){
if($this->checkValid($id)){
$this->updateUser($id);
} else {
// an advantage of this is now we can know exactly which ID failed,
// because we have the $id variable
}
}

How can I get around the lack of a finally block in PHP?

PHP prior to version 5.5 has no finally block - i.e., whereas in most sensible languages, you can do:
try {
//do something
} catch(Exception ex) {
//handle an error
} finally {
//clean up after yourself
}
PHP has no notion of a finally block.
Anyone have experience of solutions to this rather irritating hole in the language?
Solution, no. Irritating cumbersome workaround, yes:
$stored_exc = null;
try {
// Do stuff
} catch (Exception $exc) {
$stored_exc = $exc;
// Handle an error
}
// "Finally" here, clean up after yourself
if ($stored_exc) {
throw($stored_exc);
}
Yucky, but should work.
Please note: PHP 5.5 finally (ahem, sorry) added a finally block: https://wiki.php.net/rfc/finally (and it only took a few years... available in the 5.5 RC almost four years to the date since I posted this answer...)
The RAII idiom offers a code-level stand-in for a finally block. Create a class that holds callable(s). In the destuctor, call the callable(s).
class Finally {
# could instead hold a single block
public $blocks = array();
function __construct($block) {
if (is_callable($block)) {
$this->blocks = func_get_args();
} elseif (is_array($block)) {
$this->blocks = $block;
} else {
# TODO: handle type error
}
}
function __destruct() {
foreach ($this->blocks as $block) {
if (is_callable($block)) {
call_user_func($block);
} else {
# TODO: handle type error.
}
}
}
}
Coordination
Note that PHP doesn't have block scope for variables, so Finally won't kick in until the function exits or (in global scope) the shutdown sequence. For example, the following:
try {
echo "Creating global Finally.\n";
$finally = new Finally(function () {
echo "Global Finally finally run.\n";
});
throw new Exception;
} catch (Exception $exc) {}
class Foo {
function useTry() {
try {
$finally = new Finally(function () {
echo "Finally for method run.\n";
});
throw new Exception;
} catch (Exception $exc) {}
echo __METHOD__, " done.\n";
}
}
$foo = new Foo;
$foo->useTry();
echo "A whole bunch more work done by the script.\n";
will result in the output:
Creating global Finally.
Foo::useTry done.
Finally for method run.
A whole bunch more work done by the script.
Global Finally finally run.
$this
PHP 5.3 closures can't access $this (fixed in 5.4), so you'll need an extra variable to access instance members within some finally-blocks.
class Foo {
function useThis() {
$self = $this;
$finally = new Finally(
# if $self is used by reference, it can be set after creating the closure
function () use ($self) {
$self->frob();
},
# $this not used in a closure, so no need for $self
array($this, 'wibble')
);
/*...*/
}
function frob() {/*...*/}
function wibble() {/*...*/}
}
Private and Protected Fields
Arguably the biggest problem with this approach in PHP 5.3 is the finally-closure can't access private and protected fields of an object. Like accessing $this, this issue is resolved in PHP 5.4. For now, private and protected properties can be accessed using references, as Artefacto shows in his answer to a question on this very topic elsewhere on this site.
class Foo {
private $_property='valid';
public function method() {
$this->_property = 'invalid';
$_property =& $this->_property;
$finally = new Finally(function () use (&$_property) {
$_property = 'valid';
});
/* ... */
}
public function reportState() {
return $this->_property;
}
}
$f = new Foo;
$f->method();
echo $f->reportState(), "\n";
Private and protected methods can be accessed using reflection. You can actually use the same technique to access non-public properties, but references are simpler and more lightweight. In a comment on the PHP manual page for anonymous functions, Martin Partel gives an example of a FullAccessWrapper class that opens up non-public fields to public access. I won't reproduce it here (see the two previous links for that), but here is how you'd use it:
class Foo {
private $_property='valid';
public function method() {
$this->_property = 'invalid';
$self = new FullAccessWrapper($this);
$finally = new Finally(function () use (&$self) {
$self->_fixState();
});
/* ... */
}
public function reportState() {
return $this->_property;
}
protected function _fixState() {
$this->_property = 'valid';
}
}
$f = new Foo;
$f->method();
echo $f->reportState(), "\n";
try/finally
try blocks require at least one catch. If you only want try/finally, add a catch block that catches a non-Exception (PHP code can't throw anything not derived from Exception) or re-throw the caught exception. In the former case, I suggest catching StdClass as an idiom meaning "don't catch anything". In methods, catching the current class could also be used to mean "don't catch anything", but using StdClass is simpler and easier to find when searching files.
try {
$finally = new Finally(/*...*/);
/* ... */
} catch (StdClass $exc) {}
try {
$finally = new Finally(/*...*/);
/* ... */
} catch (RuntimeError $exc) {
throw $exc
}
Here is my solution to the lack of finally block. It not only provides a work around for the finally block, it also extends the try/catch to catch PHP errors (and fatal errors too). My solution looks like this (PHP 5.3):
_try(
//some piece of code that will be our try block
function() {
//this code is expected to throw exception or produce php error
},
//some (optional) piece of code that will be our catch block
function($exception) {
//the exception will be caught here
//php errors too will come here as ErrorException
},
//some (optional) piece of code that will be our finally block
function() {
//this code will execute after the catch block and even after fatal errors
}
);
You can download the solution with documentation and examples from git hub -
https://github.com/Perennials/travelsdk-core-php/tree/master/src/sys
As this is a language construct, you won't find an easy solution for this.
You can write a function and call it as the last line of your try block and last line before rethrowing the excepion in the try block.
Good books argues against using finally blocks for any other than freeing resource as you can not be sure it will execute if something nasty happens. Calling it an irritating hole is quite an overstatement.
Believe me, a hell lot of exceptionally good code is written in languages without finally block. :)
The point of finally is to execute no matter if the try block was successfull or not.
function _try(callable $try, callable $catch, callable $finally = null)
{
if (is_null($finally))
{
$finally = $catch;
$catch = null;
}
try
{
$return = $try();
}
catch (Exception $rethrow)
{
if (isset($catch))
{
try
{
$catch($rethrow);
$rethrow = null;
}
catch (Exception $rethrow) { }
}
}
$finally();
if (isset($rethrow))
{
throw $rethrow;
}
return $return;
}
Call using closures. Second parameter, $catch, is optional. Examples:
_try(function ()
{
// try
}, function ($ex)
{
// catch ($ex)
}, function ()
{
// finally
});
_try(function ()
{
// try
}, function ()
{
// finally
});
Properly handles exceptions everywhere:
$try: Exception will be passed to $catch. $catch will run first, then $finally. If there is no $catch, exception will be rethrown after running $finally.
$catch: $finally will execute immediately. Exception will be rethrown after $finally completes.
$finally: Exception will break down the call stack unimpeded. Any other exceptions scheduled for rethrow will be discarded.
None: Return value from $try will be returned.
If anyone is still keeping track of this question, you might be interested in checking out the (brand new) RFC for a finally language feature in the PHP wiki. The author already seems to have working patches, and I'm sure the proposal would benefit from other developers' feedback.
I just finished writing a more elegant Try Catch Finally class which may be of use to you. There are some drawbacks but they can be worked around.
https://gist.github.com/Zeronights/5518445

Categories