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:
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:
$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:
// 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)…
$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().
