Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:69665 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 8296 invoked from network); 18 Oct 2013 09:26:23 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 18 Oct 2013 09:26:23 -0000 Authentication-Results: pb1.pair.com header.from=nikita.ppv@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=nikita.ppv@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.128.176 as permitted sender) X-PHP-List-Original-Sender: nikita.ppv@gmail.com X-Host-Fingerprint: 209.85.128.176 mail-ve0-f176.google.com Received: from [209.85.128.176] ([209.85.128.176:48986] helo=mail-ve0-f176.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id A1/20-06505-DBEF0625 for ; Fri, 18 Oct 2013 05:26:21 -0400 Received: by mail-ve0-f176.google.com with SMTP id jz11so1832413veb.7 for ; Fri, 18 Oct 2013 02:26:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=iQS7E+5hdP0mA7p/dOONcr+A7Hbh6wWeN+CghpyJXMg=; b=1Hv3cU+82QPaRtf0Q+88I/eIEGRNqhK4uEf8YecNI1L/sUro5TeqVKwNeYKexPYH4i fdU3A9HbwSBgCMgeL1auAlsl1dP5gW+XYksZFdlNpz9KRSvExSTvm+6WJnNB69sg40gK gYHnupqablxevM7xhQmm7wF+0Gg74n893P2vQVNTSmD9M63zaVNCSqm8ZqtSZ6JdhSMj yXVpAkvObHi6FrqTrVe/ooLxfz9E3alKDgWfFwo+WJtemcjfG9GbeBXxzjWsBVG93U+m gdwm6HX9Xgg5nGOM+JqjPS8UvJnGR3/yj8jJ2eAALonUVlpUtPjth0lzdomFRsy93Ce8 hosA== MIME-Version: 1.0 X-Received: by 10.58.156.106 with SMTP id wd10mr1230662veb.7.1382088378587; Fri, 18 Oct 2013 02:26:18 -0700 (PDT) Received: by 10.220.59.1 with HTTP; Fri, 18 Oct 2013 02:26:18 -0700 (PDT) In-Reply-To: <525C631E.1050008@gmail.com> References: <525C631E.1050008@gmail.com> Date: Fri, 18 Oct 2013 11:26:18 +0200 Message-ID: To: Rowan Collins Cc: PHP Internals Content-Type: multipart/alternative; boundary=047d7b5db7beda9f8d04e9008662 Subject: Re: [PHP-DEV] Proposal to deprecate create_function() From: nikita.ppv@gmail.com (Nikita Popov) --047d7b5db7beda9f8d04e9008662 Content-Type: text/plain; charset=ISO-8859-1 On Mon, Oct 14, 2013 at 11:33 PM, Rowan Collins 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 > ]. > > 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 --047d7b5db7beda9f8d04e9008662--