PHP’s create_function() and closures

A coworker recently asked me what the difference was, functionally, between PHP’s create_function() function and traditional closures that you might find in languages with first-class functions, like Ruby or JavaScript. You can pretty easily illustrate this with a couple of examples.

First, a bit about closures. The idea with closures is that you can cleanly and readably pass around a bit of logic as an object, and any references that that object makes to variables in the surrounding scope must persist until that object is done with them.

So here’s an example in JavaScript:

function getGreeter(name) {
  return function(salutation) {
    alert(salutation + ', ' + name);
  };
}

var greeter = getGreeter('Eddy');
greeter('Hello');   // Hello, Eddy
greeter('Howdy');   // Howdy, Eddy
greeter('Bonjour'); // Bonjour, Eddy

Here’s the closest equivalent in PHP:

$code = '$name, $salutation', 'print $salutation . ', ' . $name;';
$greeter = create_function($code);
$greeter('Eddy', 'Hello');
// etc.

And that’s a callback, not a closure. In JavaScript the garbage collector reclaims the memory used by the anonymous “greeter” function… but in PHP, functions get declared and stay declared, so every time you call create_function(), you increase the memory usage.

It gets worse. This is basically what PHP does internally:

function create_function($args, $code) {
    // create a random $functionName
    eval('function ' . $functionName . '($args){$code}');
    return $functionName;
}

Yeah, the entire thing is evaluated. So not only does it not get garbage collected, but it has all the traditional problems of eval()—it’s slow, difficult to debug, and uncacheable by bytecode caches like APC. Problems that closures don’t have in other languages.

It’s why you can do something like this (which works on the same principle as SQL injection)…

$code = 'print "I print repeatedly.\n"; } print "I print once.\n"; if (false) {';
$function = create_function('', $code);
call_user_func($function);
call_user_func($function);
call_user_func($function);

// I print once.
// I print repeatedly.
// I print repeatedly.
// I print repeatedly.

…and why you should never use create_function().

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!

Tags: , ,

8 comments

  1. Hey

    It is really very important post for php and javascript. But can any one please explain the use of create_function() in real time applications by giving some example codes.

    Because the function is very powerful but How and where to use it without losing the performance of application is much important.

    once again thank you for such a wonderful post

  2. Hi Roy,

    The point is that you shouldn’t use create_function(). It was a poorly-conceived function created to give some vague semblance of lambda functionality. Avoid it. True lambda functions are coming in PHP 5.3; for anything else, create a regular, named function.

  3. I which they would think _before_ piling even more shit on what’s supposed to be nothing but a template language.

  4. And an alternative solution would be?

  5. how about this ….

    var func = new Function( $a, $b, $code );
    func( 'foo', 'bar' );
  6. a lo mejor te has puesto de esta manera después de mirar redtube ya que a mi me suele acontecer de vez en cuando ja ja ja.

  7. PrcatAPicuLizat

    Thanks for posting this comparison.

    You can translate first JS example into PHP with just little syntactic sugar:

    function getGreeter($name) {
     return function($salutation) use($name) {
       echo $salutation . ', ' . $name . "\n";
     };
    }

    $greeter = getGreeter('Eddy');
    $greeter('Hello');   // Hello, Eddy
    $greeter('Howdy');   // Howdy, Eddy
    $greeter('Bonjour'); // Bonjour, Eddy

    PHP Closures can return arrays – so common Javascript way of making inner function available is also possible:

    function getGreeter($name){
     return array( 'run' => function($salutation)use($name) {
      echo $salutation . ', ' . $name . "\n";
    });
    }

    $greeter = getGreeter('Eddy');
    $greeter['run']('Hello');   // Hello, Eddy
    $greeter['run']('Howdy');   // Howdy, Eddy
    $greeter['run']('Bonjour'); // Bonjour, Eddy

    Last example can be rewritten “oop style”:

    class getGreeter {
     function __construct ($name) { $this->NAME = $name; }
     function run($salutation) {
       echo $salutation . ', ' . $this->NAME . "\n";
     }
    }

    $greeter = new getGreeter('Eddy');
    $greeter->run('Hello');   // Hello, Eddy
    $greeter->run('Howdy');   // Howdy, Eddy
    $greeter->run('Bonjour'); // Bonjour, Eddy

Leave a comment