Programming without "finally" - php

I don't have the required version of PHP that supports finally, so I am wondering if this:
try {
work();
} catch (Exception $e) {
cleanup();
throw $e;
}
cleanup();
is exactly the same as
try {
work();
} finally {
cleanup();
}

The point of the finally block is to execute regardless of what happens in the try block, or in following catch cases. So if you think about it, the code in the finally block is executed either after a successful try block execution, or after any exception was thrown. So if you write it just as you did in your solution, then you do indeed mimic the situation exactly. If there is no exception, the code after the try/catch structure is executed; and if there is an exception—any exception—you also execute it.
I think the only situation which the finally support may rescue you from, which your version inherently can’t, is when you are actually aborting the outer execution stack early. For example if this code is inside a function and you are returning from within the try block, then the finally would still be executed, but in your manual implementation it of course couldn’t.
So if you make sure that you do not leave early, then yes, it should work in the same way.
There are not many ways to leave a function early that don’t throw an exception; return is the most obvious and aborting the program with exit, die or similar would be another.

Finally code blocks execute always - if there's an exeption, and if there isn't. But if you catch an exeption and do cleanup() after catch block, then yes - it's basically the same thing.

From the PHP docs:
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.
If you look at the examples, you'll notice that the finally block will always execute even if the exception is caught. However, when there is an exception, the code will not resume, so the finally block is a good way to ensure that certain lines of code are always executed even if there is an exception.
The finally block will matter if your catch block uses a return function or something like that. Otherwise, there is no difference between putting your cleanup in the finally block or after your try/catch
Here's the example in question from the doc comments:
Just an example why finally blocks are usefull (5.5)
<?php
//without catch
function example() {
try {
//do something that throws an exeption
}
finally {
//this code will be executed even when the exception is executed
}
}
function example2() {
try {
//open sql connection check user as example
if(condition) {
return false;
}
}
finally {
//close the sql connection, this will be executed even if the return is called.
}
}
?>

Generally, yes.
Most of times, both examples work equivalently:
<?php
function work_success() {
echo 'working' . PHP_EOL;
}
function work_fail() {
echo 'working with fail' . PHP_EOL;
throw new Exception('exception');
}
function cleanup() {
echo 'cleanup' . PHP_EOL;
}
Code without finally:
try {
work();
} catch (Exception $e) {
cleanup();
throw $e;
}
cleanup();
Code with finally:
try {
work();
} finally {
cleanup();
}
Results when work = work_success for both finally and non-finally versions:
working
cleanup
Results when work = work_fail for both finally and non-finally versions:
working
cleanup
Exception: exception
However, there are caveats.
Like #poke said, using your examples together with control flow mechanisms might get funny results. Here's an illustration of this using simple return statement:
function test()
{
try {
return 'success';
} catch (Exception $e) {
cleanup();
throw $e;
}
cleanup();
}
echo test();
This will output just success. cleanup() won't get fired unless an exception is thrown. According to prior examples, equivalent finally counterpart to above example would look like this:
function test()
{
try {
return 'success';
} finally {
cleanup();
}
}
echo test();
Note that this will execute cleanup() regardless of any exceptions, so the output will be:
cleanup
success
For some people it's suprising that code in finally block is executed prior to return statements. As long as you are aware of this, there should be no problems.

Related

Why use the "finally" keyword? [duplicate]

This question already has answers here:
Why do we use finally blocks? [duplicate]
(11 answers)
Closed 3 years ago.
I understand what the "finally" keyword is used for in various languages, however, I struggle to understand why you would use it outside of there being a formatting preference in taste.
For instance, in PHP:
try {
possibleErrorThrownFunction();
}
catch (CustomException $customException) {
// handle custom error
}
catch (Exception $exception) {
// handle the error
}
finally {
// run this code every single time regardless of error or not
}
What's the difference between what this code is doing and this?
try {
possibleErrorThrownFunction();
}
catch (CustomException $customException) {
// handle custom error
}
catch (Exception $exception) {
// handle the error
}
// run this code every single time regardless of error or not
Doesn't that last line always get run anyway due to the error being caught? In which case, there is no case to really use finally unless you just want to maintain a code-style formatting?
An example of a case where a finally statement is necessary and distinct from just putting code after try/catch statements would be helpful if I am missing something here.
Short Answer
Finally blocks are guaranteed to run no matter what happens inside of the try and catch blocks, before allowing the program to crash.
This is sort of explained here: https://www.php.net/manual/en/language.exceptions.php though the explanation isn't particularly detailed.
Some More Detail
One example that comes to the top of my head is if you are dealing with input/output streams or something similar that has to be closed after use in order to avoid a memory leak. To use your example:
try {
memoryUser.startReading(someFileOrSomething);
}
catch (CustomException $customException) {
// handle custom error
}
catch (Exception $exception) {
// handle the error
invisibleBug.whoops(); // i.e. something goes wrong in this block
}
memoryUser.Close(); // because something went wrong in the catch block,
// this never runs, which, in this case, causes a memory leak
In this case, wrapping the memoryUser.Close(); in a finally block would ensure that that line would run before the rest of the program exploded, preventing the memory leak even in an otherwise catastrophic failure.
TL;DR
So a lot of the time, people put the finally block there to ensure an important line runs, even if they overlooked something in the catch blocks. This is how I've always seen it used.
Hopefully this helps :)
What's special about a finally {} block is that it will always run at the end of the try {} block.
It will run if the code in the try {} block completes successfully.
It will run if the code in the try {} block throws an exception that was caught by a catch {}. (The finally {} runs after the catch {}.)
It will run if the code in the try {} block throws an exception that wasn't handled by any catch {} block, or if there weren't any at all. (The finally {} block runs before the exception is propagated to the caller.)
It will run if the code in the try {} block throws an exception, and the code in the catch {} throws another exception (or rethrows the same exception).
It will even run if the code in the try {} block, or in a catch {} block, uses return. (Just as with an uncaught exception, the finally {} runs before the function actually returns.) The finally {} block can even use return itself, and its return value will override the value that the other block tried to return!
(There is one edge case where a finally {} block won't run, and that's if the entire process is destroyed, e.g. by being killed, or by calling exit() or die().)

Understanding try and catch

This probably sounds ridiculous. However, if you don't ask you'll never learn.
I'm relatively new to PHP and self-taught so I haven't exactly learnt everything "to the book".
Is the following required:
try {
}
catch {
}
Am I right in thinking that the try will try to "execute" the code within the brackets and the catch will try and catch the result of the outcome? If there is nothing to catch then it will throw an error?
The first assumption is correct: the code in try will be attempted to run.
However, if no error is thrown, then the block exits normally. If there is an error thrown, then the try execution ends early and goes into the catch block. So your second idea is switched.
try catch is used for exception handling or error handling.Put your script in try block and write your custom error message in catch block.
try{
// put here script
}catch(Exception $error){
//your custom message
echo 'Caught exception: ', $error->getMessage(), "\n";
}
If your script does not execute then it will be jump catch block and access message using $error object.
What is the benefit? The benefit is the whole script will not be stop to execute. It will be continue other block.
In the try block you execute code, whenever something fails in that block it will jump to the catch block. You usually define a variable holding the exception.
So to answer your question, no it will not process the catch block when there is nothing going wrong in the try block. (unless you specifically throw an exception)
try {
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
Try block is hold the code which you want to execute. and Catch block is hold the code if you have cause any error then it will execute the catch code or error message.
Basically try and catch we are using for the error handling and avoid to break the control flow of the program and page.
Simple example:
<?php
class A {
public function getA($a = 0)
{
if ($a === 0) {
throw new ItCantBeZeroException("Message");
}
return $a;
}
}
// I want to throw default exception because I'm not sure
// am I doing it right or what can I do with bad parameter.
$a = new A;
echo $a->getA(0);
// Now, I know what I can do if developer write bad input.
// It can't be 0, so I just print my custom error message
// to my page.
try {
$a = new A;
echo $a->getA(0);
} catch (ItCantBeZeroException $e) {
echo "Parameter can't be zero. Try again.";
}
?>
You can define your own exceptions (like ItCantBeZeroException). Exceptions throw error on site (like "Message") but we can catch them and change to something we want.
You write simple class where some code must be string or integer between 0 and 20.
You use this code, but when user make variable 21, simple class throw error.
You refactor code to catch exception and try to fix code, e.g. change any integer greater than 20 to 20. Then code works properly.
Try and Catch is known as Exception Handling
According to w3schools:
Exceptions Handling are used to change the normal flow of a script if a specified error occurs.
For More:
http://www.w3schools.com/php/php_exception.asp

Extended: what's the finally keyword for?

Ok, I understand the "accepted answer" that was given for this question, but it's still not clear to me what kind of code should I put in finally blocks.
If the use of finally is to get the non-catched exceptions thrown and give a general error message for the system not explode for the user, wouldn't appear two error messages for the user if some exception was catched?
[Edit]
Like #MarkBaker said, the "finally" isn't for catch the uncaught exceptions, the generic catch(Exception $e) do that. So... for what it's useful? Or, in other words, what the finally block does that I can't do after the try/catch blocks without finally?
Maybe the following explanation will better help you understand how it works:
try {
function1();//this might throw an exception
function2();//if we want function2 to be executed regardless
//if an exception was thrown from function1() - this
//is not a good place to call it!
} catch (Exception $e) {
echo $e->getMessage();
} finally {
function2();//then the right place to write it will be in a finally clause.
}
When an exception is thrown from function1() - function2() will not be executed - the execution will "jump" to the catch section. If we want function2() to be executed regardless if an error was thrown, for example, if function1() opens a connection to the DB and runs some selects and function2() closes that connection, then we'd better place the call to function2() in the finally block that follows the catch
The 'finally' block should hold code you want executed regardless of the outcome of the try/catch block. For example, if you try to query a database and catch the error, you would still likely want to close the database connection, regardless of whether the database operation succeeded or not. See below:
open_database_conn();
try{
query_database();
return_result();
}
catch(Exception $e){
echo $e->getMessage();
}
finally{
close_database_conn();
}

PHP finally clause

What is the best practice to simulate a finally clause? I realize this could be considered related (though I don't think it's a duplicate) of this question.
However, in my case I want to handle exceptions, I want to use finally (or whatever PHP equivalent or practice) as defined by python:
A finally clause is always executed before leaving the try statement, whether an exception has occurred or not.
Just loosely writing the code after the try-catch block seems like an ugly practice to me.
In the RFC for adding finally to PHP, they suggest this workaround:
<?php
$db = mysqli_connect();
try {
call_some_function($db);
} catch (Exception $e) {
mysqli_close($db);
throw $e;
}
mysql_close($db);
So unless you upgrade to PHP 5.5 (which will contain the finally construct), this is probably your best option.
This could be considered something of a non-answer, but there are ways of structuring code that mean finally is not needed, such as the "RAII Pattern" ("Resource Acquisition Is Initialization") where cleanup of a resource is done in the destructor of a locally scoped variable representing that resource.
The idea is that if an exception rips you out of function scope, your destructor will fire, so your cleanup happens as expected. If no exception is thrown, you will reach the end of your function, and your variable will go out of scope that way.
A quick Google turned up this simple code for doing it with arbitrary callbacks.
PHP 5.5 and later do have the finally construct.
From the docs:
try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "First finally.\n";
}
If you are still stuck maintaining pre 5.5 legacy code, and you don't mind the overhead of a mandatory fake throw every call, there is always this dirty little trick.
try {
// do your worst to mess things up.
throw new Exception("finally");
} catch (Exception $e) {
//TODO: after upgrading to 5.5, make this a legit try/catch/finally
if ( ($msg = $e->getMessage()) != "finally"){
// real catch
echo "Exception doing something :" . $msg;
} else {
// quasi finally.
};
}

Error handling for functions in a catch statement

This is a piece of code that I was wondering if it should be refactored to make it more complied with the Clean Code practices.
This is a class which is responsible for refunding some orders made by customers.
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
$this->getOrdersFromDB(); //This function gets all orders from DB and sets $_orders
foreach ($this->_orders as $order) {
try {
$order->refund(); //Some lines may throw an exception when refunded due to some business logic (ex. the order was already shipped)
$this->updateOrderStatus('refunded')
} catch (Exception $e) {
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
}
of course this code is highly simplified than my original code.
My main problem is if $order->refund(); throws an exception it will be caught and logged to DB then a mail is sent. However what if $this->logError($e); itself throws an exception? or what if the mail server was down and an exception was thrown?
Better what if the DB was down itself and $this->getOrdersFromDB(); throws an exception?
My first solution was to wrap everything in one big try{}catch{}:
public function refundOrder() {
try {
$this->getOrdersFromDB(); //This function gets all orders from DB and sets $_orders
foreach ($this->_orders as $order) {
$order->refund(); //Some lines may throw an exception when refunded due to some business logic (ex. the order was already shipped)
$this->updateOrderStatus('refunded')
} catch (Exception $e) {
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
But that would mean if one order fails then all fails!! Should I put 2 try{}catch{} one for the whole function and the other for each order? But in this case too the functions in the catch might throw an exception that won't be caught.
Note:
The application is built using Zend framework 1.11.11.
Thanks in advance.
There is no magic bullet to solve such issues. If a function can throw and you care about it, you have to wrap try/catch around it -- simple as that.
To move into specifics: it's not really possible to evaluate the merits of this or that approach without having much more information about the architecture of your app, but here are some general suggestions:
Do check prerequisites before even calling refundOrder. Make sure that orders have been loaded successfully; make sure the orders you are going to operate on are all refundable (what's the purpose of trying to refund an order that is not refundable due to business logic? shouldn't the user/operator be notified of this before a refund is attempted?).
Do use more than one levels of try/catch, but perhaps not all inside refundOrder. The outer block is meant to catch any errors that were really unexpected, so what's the point in catching them inside refundOrder only? Don't you want to do that in other parts of you app as well? The innermost try/catch is necessary so that one non-refundable order won't kill all the process.
If you need to log and mail every exception, then you need something like this:
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
try {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
} catch(Exception $e) {
# deals with unexpected bugs
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
But you have to put a try/catch inside log and mail methods to prevent them to throw any exception when servers are offline, for example. If you don’t, the $orders loop will be stopped when log/mail fails.
If you need to log/mail only your business exception in refund() method, then you need something like this:
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
}
}
Any other exception will lead to an http 500 – internal server error page, which is usually what you want, because it’s an unexpected bug.
There’re other ways to handle this, but as you see, it depends on your needs.
As logError($e) and sendMailToAdmin() are probably functions that are used in last resort, typically in try/catch blocks, I would ensure that they never throw an Exception.
function logError($e)
{
try
{
//your logic that may throw an Exception here
}
catch {}
}
function sendMailToAdmin($e)
{
try
{
//your logic that may throw an Exception here
}
catch {}
}

Categories