On Mon, Oct 14, 2013 at 11:33 PM, Rowan Collins <[email protected]>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