Re: Proposal to deprecate create_function()

From: Date: Fri, 18 Oct 2013 09:26:18 +0000
Subject: Re: Proposal to deprecate create_function()
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-69665@lists.php.net to get a copy of this message
On Mon, Oct 14, 2013 at 11:33 PM, Rowan Collins <rowan.collins@gmail.com>wrote: > 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/** > > 1d57b16e69dfd8d93dd6e4a354d3ed**20bd21494d<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, > I'm +1 on deprecating create_function. It is a security liability, it is slow and it eats memory. We have better alternatives nowadays (anonymous functions) and in cases where you need wide-range version support (including PHP 5.2 or lower) you are still better off using a normal, named function rather than create_function. You can even replicate the exact behavior (minus the hiding from get_defined_functions) with just four lines of code (though I have no idea what you could possibly need this for): function create_function($params, $code) { static $i = 0; $name = "create_function_" . $i++; eval("function $name($params) { $code }"); return $name; } I tried to look on Github what people currently use create_function for, but with little success. Nearly all results I get are uses in the php testsuite (copied over to various projects). The only other use case I saw was in conjunction with the WordPress add_action() function. In this case the create_function call could always be replaced directly with an anonymous function (i.e. it didn't need any magic create_function capabilities). Nikita

« previous php.internals (#69665) next »