Recursive Closures in PHP 5.3

With the release of PHP 5.3.3 the other day and the announcement of the end of active support for the PHP 5.2 branch I thought it would be a good time to do a bit more experimenting with the new features in PHP 5.3. I would have done this sooner but the hosting company we use at work is still using the 5.2 branch. I’d also like to upgrade my Zend Certification to the 5.3 version when the new exam becomes available. Our hosting company also has the setting ‘magic_quotes_gpc’ enabled in php.ini and one thing all of my projects have in them is code to remove the quotes added so I can handle appropriate escaping myself. I use the following code from the PHP manual:

<?php
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value) {
return (is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value));
}
$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
}
?>

This works perfectly but it does end up creating a function in the global namespace which is only called once. A perfect job for a closure.

What is a closure?

A closure is a special type of anonymous function that encapsulates one or more variables from the scope it is created in when it is created. The name comes from the idea that this kind of function closes over these variables. This is not the same as passing an argument to a function or using the global keyword. Inside the closure the variable encapsulated contains the value its ‘parent’ had at the time the closure was created. Changes to the variable inside the closure do not affect the variable outside the closure. It’s this behaviour that differentiates a closure from an anonymous function (the PHP manual seems to use the terms interchangeably).

Stripping slashes the PHP 5.3 way

I found the technique for creating a recursive closure in PHP on Stack Overflow. Here’s my code to strip slashes added by magic_quotes_gpc using a recursive closure:

<?php

if (get_magic_quotes_gpc()) {
 $strip_slashes_deep = function ($value) use (&$strip_slashes_deep) {
return is_array($value) ? array_map($strip_slashes_deep, $value) : stripslashes($value);
 };
 $_GET = array_map($strip_slashes_deep, $_GET);
 $_POST = array_map($strip_slashes_deep, $_POST);
 $_COOKIE = array_map($strip_slashes_deep, $_COOKIE);
 }
?>

Variables are enclosed within a closure using the ‘use’ keyword. The thing to note here is that the closure is enclosed within itself (!) and that to achieve this it needs to be passed by reference. Without this the PHP parser generates a warning saying that the variable ‘$strip_slashes_deep’ does not exist. I think that this is because of the way values are encapsulated within closures. They are encapsulated at the point the closure is created and in the code above the variable $strip_slashes_deep does not exist at the point the closure is created. It is only created as the return value of creating the closure, ie. the closure itself. Passing the closure by reference avoids this issue entirely.

The real beauty of this code for me is that it avoids polluting the global namespace with a function that is used only once. As soon as the variable $strip_slashes_deep falls out of scope it, and the closure contained in it, are destroyed. This technique could be used to create any number of recursive closures. It just so happens that the example I could think of for this was to strip slashes added by magic quotes. I’d be curious to know of any other use cases anyone can think of for this technique or any other comments people may have. I still find the concept of recursive closures encapsulating themselves slightly mind boggling and may have muddled up some of my terminology as a result.

Update: PHP 5.4

With the recent release of PHP 5.4 there’s a new way to call a recursive lambda/closure as long as you’re using OOP. PHP 5.4 allows the ‘$this’ variable to be accessed inside a lambda function. It also allows a closure to be duplicated, binding a new ‘$this’ variable to it (hopefully the example below will make all of this clearer). With this in mind the following code allows a closure to be passed to an object constructor and then to call itself recursively as a method of the object it’s passed to:


<?php
class foo {

 protected $bar;

 public function __construct(Closure $closure)
 {
 $this->bar = Closure::bind($closure, $this, 'foo');
 }

 public function __call($method, $args)
 {
 if (is_callable(array($this, $method)))
 return call_user_func_array($this->$method, $args);
 }
}

$foo = new foo(function($value){
 //Use stripslashes here as an example but could be any function/operation.
 return (is_array($value) ? array_map($this->bar, $value) : stripslashes($value));
});

$values = [
 '\foo',
 '\bar',
 ['O\'Reilly', '\\ABC']
];
$processed = $foo->bar($values);
var_dump($processed);

While this works I’d love to know if anyone can think of a practical use case for this!

11 thoughts on “Recursive Closures in PHP 5.3

    1. Hi Lode,

      Thanks for the comment. I should have made it clearer in the post that the code is merely an example for the technique. I used the magic_quotes example because a) it’s the one that came to mind at the time and b) my hosting company has that directive enabled. Unfortunately although magic_quotes are deprecated I can’t see them disappearing any time soon, at least not until every hosting company and server is running PHP 6 (or whatever the next version is going to be called). Personally, I can’t wait for the time when magic_quotes are removed from PHP entirely.

      Thanks for the info about keys and magic_quotes-I wasn’t aware of that. I’m not sure if I’m too worried about that though. I can’t think of a time when I’ve written a POST, GET or Cookie key that contained characters that would need to be escaped by magic_quotes. One could argue that there’s a potential security vulnerability since there’s nothing to stop an attacker submitting arbitrary key => value pairs. I would argue though that it’s the job of the developer to only work with parameters that they’re expecting in the request, filtering these in the strongest ways possible. For me the code in the post gives a good start by removing any slashes before any parameters in the request are filtered.

  1. Even though magic_quotes_* are still enabled on most hosted servers.
    They are easely disabled in .htaccess 1 simple line:
    php_value magic_quotes_gpc Off

    A lot better then filtering them on demand. this will disable them a lot more globally.

    Anyways a nice example of using a reference closure recursion.

  2. Great article.
    Thank you very much for pointing out the new PHP 5.4 Closure bind/bindTo methods – I did not know that they existed, and, after a bit more research into the capability of these methods, they have helped me quite a bit.

    I have a single object, called EventContainer, that implements the observer/listener designer pattern and, combined with a trait to pass the container around my application, makes working with the observer design pattern extremely easy.

    EventContainer is a single object that holds all events, organized by event names. Each event name can hold an unlimited amount of closures. An object can notify the event container of an event, and then all the closures will shoot off.

    What the bind method allows me to do is allow all closures sent to the event container to seamlessly use the $this keyword and act as though the event code is being run directly in the object that triggered the event – even though all closures are stored in and run by the event container.

    Thanks again.

Leave a Reply