As of PHP 5.3 web developers can use a wonderful feature of the language, the __invoke()
magic method. This enables PHP to provide the Closure class and based on it the ability to define anonymous functions. Anonymous function is a powerful language construct, it can come handy in a number of ways. For example, it makes the code easier to manage by letting you define locally visible small functions inside a method or a function. This is useful when you want to sort an array by some special property of the elements in it – you don’t have to define a named function or method in your global scope or in a class, you can just hide the comparison callback inside the method that needs a specially sorted array. But anonymous functions combined with other language constructs, can even be used to emulate some features missing from PHP: finally
for instance.
Some say the need for a finally
keyword is the result of bad design. Most people would use finally
in a similar situation like this to avoid code duplication in the catch
block and after the try
-catch
statement:
class A
{
public function doSomething()
{
$my_resource = open_my_resource();
try
{
$result = use_my_resource($my_resource);
}
catch (Exception $e)
{
free_my_resource($my_resource);
throw $e;
}
free_my_resource($my_resource);
return $result;
}
}
Using finally
the above code snippet would look like this:
class A
{
public function doSomething()
{
$my_resource = open_my_resource();
try
{
$result = use_my_resource($my_resource);
}
finally
{
free_my_resource($my_resource);
}
return $result;
}
}
In this situation rethinking the design can help avoid the need for finally
:
class MyResource
{
public function __construct()
{
$this->resource = open_my_resource();
}
public function __destruct()
{
free_my_resource($this->resource);
}
public function use()
{
return use_my_resource($this->resource);
}
private $resource;
}
class A
{
public function doSomething()
{
$my_resource = new MyResource();
$result = $my_resource->use();
return $result;
}
}
But sometimes life’s not that easy. Sometimes your hands are bound, sometimes it’s not that trivial to circumvent the need for finally
. That is the case when a nice hack based on closures can help:
class FinallyEmulator
{
public function __construct($callable)
{
if (!is_callable($callable))
throw new ErrorException('Ooops, bad callable.');
$this->callable = $callable;
}
public function __destruct()
{
$this->invoke();
}
public function __invoke()
{
$this->invoke();
}
private function invoke()
{
if ($this->callable)
{
$callable = $this->callable;
$this->callable = NULL;
call_user_func($callable);
}
}
private $callable;
}/**
* Note that return value of $callable is totally ignored.
*/
function finally($callable)
{
return new FinallyEmulator($callable);
}
Using that class you can transform the second code snippet in this blog post like this:
class A
{
public function doSomething()
{
$my_resource = open_my_resource();
$finally = finally(function () use ($my_resource)
{
free_my_resource($my_resource);
});
try
{
$result = use_my_resource($my_resource);
}
catch (Exception $e)
{
fprintf(STDERR, "Error: %s\n", $e->getMessage());
throw $e;
}
$finally();
return $result;
}
}
Note that this workaround does not handle the return
-inside-finally
problem at all as you cannot return from the function from the simulated finally
block