Alex Rivera | Logout

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

Asked 2009-05-29T17:31:43.983
56

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?

Edit
Report

2 Answers

9

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 with

answered 2012-02-11T22:48:30.473
0

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.

answered 2012-07-31T08:05:55.470

Your Answer