Most modern languages have a construct that allows code to run at the end of a block regardless of how flow leaves a block. This allows code to reliably close resources, perform rollbacks, and otherwise maintain invariants relatively easily, even in the presence of exceptions.
Exceptions were added to PHP in PHP5, allowing blocks of PHP to terminate abruptly. Constructs like
1 2 3 4 5 | <?php $h = fopen("config.ini"); $str = some_local_function($h); fclose($h); ?> |
do not guarantee that $h gets closed reliably: if some_local_function throws an exception, flow never reaches line 4 and never closes the handle. For most things, this isn’t actually as big a deal as it would be in other languages: connections, file handles, and other resources are all closed at the end of each request anyways.
However, sometimes you care what order resources are closed in, or you want to perform some cleanup actions with a resource before closing it, and then the lack of a finally clause hurts. One PHP project I’ve worked on talks to an AMQP broker; AMQP has a defined connection teardown process that’s necessary to verify that published messages are actually being processed. The ideal way to handle that would look like:
1 2 3 4 5 6 7 8 | <?php $amqp = new AMQPConnection(/*...*/); try { /* Publish messages using $amqp */ } finally { $amqp->close(); } ?> |
Without finally (or with blocks/using statements, for the Python and C# programmers out there), the obvious solution is much uglier:
1 2 3 4 5 6 7 8 9 10 | <?php $amqp = new AMQPConnection(/*...*/); try { /* Publish messages using $amqp */ } catch (Exception $e) { $amqp->close(); throw $e; } $amqp->close(); ?> |
Note the near-mandatory duplication.
Of course, it’s possible to work around the lack of automatic resource management syntax by using an idiom from, of all things, C++:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php class Closing { private $closeable; function __construct($closable) { $this->closeable = $closeable; } function __destruct() { $this->closeable->close(); } } /* ... */ $amqp = new AMQPConnection(/*...*/); { $close_amqp = new Closing($amqp); /* Publish messages using $amqp */ } ?> |
However, this relies on understanding the interactions between scope, object lifespans, and PHP’s optional garbage collector, which are non-trivial.
The PHP development team doesn’t think this is a problem.