Hi All,
(First, a quick aside: I'm new here, so let me know if I'm treading on any toes or failing to do my homework properly. Also, apologies for long-windedness; it's a personal flaw.)
I would like to propose that create_function() be officially deprecated, to encourage people to use the much safer and more powerful anonymous functions we've had since 5.3, and eventually allow this relic to be removed from the language.
In case any of you aren't familiar with the details, create_function, according to Zeev's comment in the source "Creates an anonymous function, and returns its name (funny, eh?)". It does this by wrapping some boilerplate around two strings provided by the user, and eval()ing the result to (hopefully) create a function called __lambda_func; it then renames this to a unique name beginning with a null byte, so that it can't conflict with any "real" functions, and returns the new name as a string.
Until PHP 5.3, this was the only way to dynamically create a callback function, and is thus a widely used feature, so it should not be removed in a hurry. Many projects (e.g. Wordpress) still support PHP 5.2, so cannot switch over to true anonymous functions yet; but we can hope that most people will have abandoned 5.2 by the time 5.7 or 5.8 comes around, and re-evaluate then.
The argument for deprecating it is largely the same as for the /e modifier in preg_replace - namely that it's a wrapper around eval(), with all the dangers that brings. In fact, I've seen a few people trying to "fix" uses of preg_replace using create_function() to create the argument for preg_replace_callback()!
Specifically:
* It performs absolutely no checks before eval()ing the string. It is
therefore trivial for code to end up injected into it, and even be
run immediately, e.g. create_function('', '} echo "hi"; if (0) {');
[http://3v4l.org/YtmVT]
* Since the function body is simply a string, the only way to "close
over" a variable is to use var_export, serialize, or similar. Even
string variables need careful escaping.
* The function name it creates, although guaranteed unique, is
entirely predictable, and the function exists in the global
namespace. It's impossible to truly isolate it to a particular scope.
* The function, once created, is never destroyed, so repeated use of
create_function "leaks" memory.
A seeming alternative to deprecating it would be to reimplement it in terms of closures. However, this would be the worst of both worlds: on the one hand, it would still need to eval() its body argument, so have much the same security risk; on the other, it would still represent a BC break, because it would have a different return type. It is, for instance, possible to reference one "anonymous" function within another, by judicious use of var_export or similar to inject the null-prefixed string into the function body; I doubt anyone heavily uses such tricks, but if they did, create_function() returning a closure object would be more irritating than it not existing at all.
I mentioned in StackOverflow chat that the documentation still had examples using create_function, and NikiC went ahead and fixed several, as well as adding a warning to the top of the documentation page. [https://github.com/salathe/phpdoc-en/commit/1d57b16e69dfd8d93dd6e4a354d3ed20bd21494d].
I think it would be sensible to take this a step further and emit an E_DEPRECATED message if it is used in PHP 5.6, and add to the warning that it may be removed in a future version of PHP.
If anyone can think of any counter-arguments - and in particular, any uses of create_function() which can't trivially be replaced with either a true closure or a direct call to eval() - I would be interested to hear them.
Regards,
--
Rowan Collins
[IMSoP]