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]
(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 disagree. Verbosity is preferable to cheap one-liners. =)
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.
Would you consider drafting an RFC for this? Please also include details
on the current (post-5.3) functionality that replaces it.
--Kris
Kris Craig wrote (on 15/10/2013):
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.
Would you consider drafting an RFC for this? Please also include
details on the current (post-5.3) functionality that replaces it.
Hi Kris,
I thought that would be the way to go, and am happy to write one up. As
I say, I'm new here, and all the guidelines strongly advised to get an
initial reaction from the list first, so I thought I'd draft the key
points in an e-mail first, and make sure I wasn't wasting my time on
something that had no chance of being accepted.
Regards,
Rowan Collins
[IMSoP]
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 general: Getting rid of it is good. But mind that closures are no
full replacement as with create_function()
the code can be created on
the fly. Emulating it with eval() is also complicated as it has this
nice trick of creating function names which start with \0 and therefore
don't appear in function lists.
I don't think this is a commonly used feature, but when kicking
create_function()
we should not call closures+eval a full replacement.
johannes
In general: Getting rid of it is good. But mind that closures are no
full replacement as withcreate_function()
the code can be created on
the fly.
Yes, I agree that there is no trvial solution which is 100% feature (and
bug) compatible with create_function()
. However, I think the more
important question is whether there are any particular use cases which
can't be easily migrated to a different mechanism.
My gut feel is that at least 95% of uses of create_function are to
create dynamic callbacks for usort, preg_replace_callback, array_filter,
etc. For these uses, the implementation as an eval() is a liability, and
reimplementing with real closures is trivial (assuming no need to run on
<=5.2).
The remaining uses may be taking deliberate advantage of the fact that
it's an eval() wrapper, but most of those could in turn be trivially
replaced with a user-defined function that uses eval() to return a new
closure. Only code that is somehow relying on the fact that the return
is a string of the function name would need to worry about picking a
unique name, and an even smaller proportion of those would care that the
prefix begins with a null byte rather than some other arbitrary string.
Emulating it with eval() is also complicated as it has this
nice trick of creating function names which start with \0 and therefore
don't appear in function lists.
The only function list I know of is get_defined_functions()
, which does
indeed exclude properties with a leading null byte, via an internal
function named copy_function_name. It's not clear from the logs whether
that was a deliberate decision or a side-effect of some other use of
null bytes. Elsewhere, function_exists()
returns true for these
"anonymous" functions, and ReflectionFunction is able to see them,
although it confusingly thinks their name is still __lambda_func.
Since closures are also not visible in get_defined_functions()
, for this
to matter, somebody would have needed to write code that relied
simultaneously on their function being referable to by name and it not
appearing in that particular list.
It's certainly possible that somebody would be forced to do some more
serious rewrites if that exact combination weren't possible, but it
seems extremely unlikely to me.
Regards,
--
Rowan Collins
[IMSoP]
In general: Getting rid of it is good. But mind that closures are no
full replacement as withcreate_function()
the code can be created on
the fly.Yes, I agree that there is no trvial solution which is 100% feature (and
bug) compatible withcreate_function()
. However, I think the more important
question is whether there are any particular use cases which can't be
easily migrated to a different mechanism.
That's the actual question, why should they?
My gut feel is that at least 95% of uses of create_function are to create
dynamic callbacks for usort, preg_replace_callback, array_filter, etc. For
these uses, the implementation as an eval() is a liability, and
reimplementing with real closures is trivial (assuming no need to run on
<=5.2).
Yes, as many other new features allow cleaner codes. However I do not
see this case as good enough to add more deprecated notices to
perfectly valid codes.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
Yes, I agree that there is no trvial solution which is 100% feature
(and bug) compatible withcreate_function()
. However, I think the
more important question is whether there are any particular use
cases which can't be easily migrated to a different mechanism.
That's the actual question, why should they?My gut feel is that at least 95% of uses of create_function are to create
dynamic callbacks for usort, preg_replace_callback, array_filter, etc. For
these uses, the implementation as an eval() is a liability, and
reimplementing with real closures is trivial (assuming no need to run on
<=5.2).
Yes, as many other new features allow cleaner codes. However I do not
see this case as good enough to add more deprecated notices to
perfectly valid codes.
I guess to me it seems much the same as deprecating the /e modifier in
preg_replace: code using it right now largely works, but it presents a
security risk that many users probably don't appreciate.
I wasn't subscribed when that was being discussed, so if there are
points from that discussion which would be pertinent here, I'd welcome
links/summaries.
The only real difference I can see with create_function is that it
is/was more widely used; is that your concern, or do you see a
fundamental difference between the two situations?
--
Rowan Collins
[IMSoP]
On Thu, Oct 17, 2013 at 8:31 AM, Rowan Collins rowan.collins@gmail.com
wrote:Yes, I agree that there is no trvial solution which is 100% feature (and
bug) compatible withcreate_function()
. However, I think the more important
question is whether there are any particular use cases which can't be
easily migrated to a different mechanism.That's the actual question, why should they?
My gut feel is that at least 95% of uses of create_function are to create
dynamic callbacks for usort, preg_replace_callback, array_filter, etc.
For
these uses, the implementation as an eval() is a liability, and
reimplementing with real closures is trivial (assuming no need to run on
<=5.2).Yes, as many other new features allow cleaner codes. However I do not
see this case as good enough to add more deprecated notices to
perfectly valid codes.I guess to me it seems much the same as deprecating the /e modifier in
preg_replace: code using it right now largely works, but it presents a
security risk that many users probably don't appreciate.I wasn't subscribed when that was being discussed, so if there are points
from that discussion which would be pertinent here, I'd welcome
links/summaries.The only real difference I can see with create_function is that it is/was
more widely used; is that your concern, or do you see a fundamental
difference between the two situations?
I do. create_function is used for many very valid use cases, safely,
much more than /e ever was (and its security impact was much bigger).
Deprecating it does not help us nor our users at this stage.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
The only real difference I can see with create_function is that it is/was
more widely used; is that your concern, or do you see a fundamental
difference between the two situations?
I do. create_function is used for many very valid use cases, safely,
much more than /e ever was (and its security impact was much bigger).
Deprecating it does not help us nor our users at this stage.
If create_function did not exist, would any of those use cases persuade
you that it should?
If not, it sounds like existing usage is the concern. Which is not to
belittle the importance of that, I just want to be sure we're coming
from the same place.
--
Rowan Collins
[IMSoP]
The only real difference I can see with create_function is that it is/was
more widely used; is that your concern, or do you see a fundamental
difference between the two situations?I do. create_function is used for many very valid use cases, safely,
much more than /e ever was (and its security impact was much bigger).
Deprecating it does not help us nor our users at this stage.If create_function did not exist, would any of those use cases persuade you
that it should?
Not with latest PHP releases, but that's the point: we try to keep BC.
--
Pierre
@pierrejoye | http://www.libgd.org
If create_function did not exist, would any of those use cases
persuade you that it should?
Not with latest PHP releases, but that's the point: we try to keep BC.
Well, to an extent - it is not true that any PHP script which works in
PHP 5.2 will work in PHP 5.5, let alone work identically. For instance,
call-time pass-by-reference causes a fatal error in PHP >= 5.4; unlike
calls to create_function, it's tricky to search for code that used that,
and to be confident of the implications of changing it.
So it is not a case of "thou shalt not break BC", but a case of "how big
a BC break is this?" Obviously, there are other questions (e.g.
challenging the reasons for removing it), but I'd like to break this
one apart a bit:
Q: Is it difficult to upgrade code to not use the feature?
A: For 95%+ of cases, my contention is that refactoring use of
create_function()
to use closures is pretty trivial. A few cases which
explicitly used its quirks may need a wrapper around eval() etc. Nobody
has yet piped up with a use case which would rely on the
harder-to-emulate aspects of the current implementation.
Q: Can code be migrated to the new solution in advance?
A: Yes, for all supported versions of PHP...
Q: ...OK, but what about code bases which still run on older releases?
A: Private code bases will generally either run entirely on an old
release (in which case BC isn't an issue) or upgraded entirely to a new
release (in which case BC is a matter of upgrade cost). Public code,
however, is often written to support a wide range of releases, to
maximise the install base. An obvious example is Wordpress, which
currently has a minimum version requirement of 5.2.4, and supported PHP
4 until remarkably recently.
If create_function were removed in version X (which is not right now),
there would be an issue if a project such as Wordpress decided to
support both 5.2 and version X from the same code base. The code base
could then contain neither create_function nor anonymous functions -
unless some wrapper(s) were written which abstracted both, which is
possible for all but the most exotic usages.
For some value of X, it is reasonable to assume that this will not be
the case, although when depends a lot on external factors. I don't know
whether "X is too far in the future" should be considered an argument
against deprecating or not. On the one hand, a long period of
deprecation is a good thing, as it gives people time to plan a strategy
for the eventual removal; on the other, it makes it uncertain whether
you should pay attention to the deprecation yet or not.
Q: How much legacy code is "out there" that uses the feature?
A: This is probably the biggest issue, and the number one reason for not
removing it would be the inconvenience of editing old code in order to
run it on newer systems. Again, we are trying to predict future trends
here: at the time of version X, how much old code will be around for
which removing create_function would be a significant part of the
upgrade cost?
I'm not proposing to know the "right" answer here, but I'd be interested
to hear something other than a gut reaction of exactly why deprecating
it would be a bad idea (or an insufficiently good one).
Apologies again for long-windedness.
Regards,
--
Rowan Collins
[IMSoP]
On Thu, Oct 17, 2013 at 11:24 AM, Rowan Collins rowan.collins@gmail.com
wrote:If create_function did not exist, would any of those use cases persuade
you that it should?Not with latest PHP releases, but that's the point: we try to keep BC.
Well, to an extent - it is not true that any PHP script which works in PHP
5.2 will work in PHP 5.5, let alone work identically. For instance,
call-time pass-by-reference causes a fatal error in PHP >= 5.4; unlike calls
to create_function, it's tricky to search for code that used that, and to be
confident of the implications of changing it.
Comparing a widely used feature, working well with something that
never really worked (and why we have removed it) is hardly a good
argument to remove create_function :-)
So it is not a case of "thou shalt not break BC", but a case of "how big a
BC break is this?" Obviously, there are other questions (e.g. challenging
the reasons for removing it), but I'd like to break this one apart a bit:
It is, create_function works and is widely used. We can provide
good/better documentation to inform our users about better, cleaner,
sexier ways to achieve the same but deprecating it in a 5.x release is
not going to work out well.
Q: Is it difficult to upgrade code to not use the feature?
A: For 95%+ of cases, my contention is that refactoring use of
create_function()
to use closures is pretty trivial. A few cases which
explicitly used its quirks may need a wrapper around eval() etc. Nobody has
yet piped up with a use case which would rely on the harder-to-emulate
aspects of the current implementation.
Code should not be updated in the 1st place unless there is a really
critical issue, something we absolutely have to change. That's not the
case here, we do not enforce good practices (or we could enforce so
many other things in the language ;).
Also I think we disagree on that, we discussed pretty much all points,
let face it :). I have to suggest to create a RFC if you feel like it
has to be deprecated and see what other developers want.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
Well, to an extent - it is not true that any PHP script which works in PHP
5.2 will work in PHP 5.5, let alone work identically. For instance,
call-time pass-by-reference causes a fatal error in PHP >= 5.4; unlike calls
to create_function, it's tricky to search for code that used that, and to be
confident of the implications of changing it.
Comparing a widely used feature, working well with something that
never really worked (and why we have removed it) is hardly a good
argument to remove create_function :-)
Absolutely, every proposal has to be evaluated on its merits, and that
was just an example of a different situation where different conclusions
were reached. But "it works" seems a little too superficial to me, and I
wanted to tease out the details of this particular case.
To continue with the call-time pass-by-reference example, it was
perfectly possible to write code which relied on that feature; it just
wasn't a terribly good idea. In fact, I came upon this manual page the
other day: http://php.net/debug_zval_dump The examples rely on the fact
that the caller can decide whether something is passed by value or
reference. In PHP >=5.4, that function is slightly more useless than it
was before.
--
Rowan Collins
[IMSoP]
Am 17.10.2013 17:47, schrieb Pierre Joye:
In general: Getting rid of it is good. But mind that closures are no
full replacement as withcreate_function()
the code can be created on
the fly.Yes, I agree that there is no trvial solution which is 100% feature (and
bug) compatible withcreate_function()
. However, I think the more important
question is whether there are any particular use cases which can't be
easily migrated to a different mechanism.That's the actual question, why should they?
My gut feel is that at least 95% of uses of create_function are to create
dynamic callbacks for usort, preg_replace_callback, array_filter, etc. For
these uses, the implementation as an eval() is a liability, and
reimplementing with real closures is trivial (assuming no need to run on
<=5.2).Yes, as many other new features allow cleaner codes. However I do not
see this case as good enough to add more deprecated notices to
perfectly valid codes.
Please note that there are open bugs with "create_function" the should
than be fixed including memory issue.
Cheers,
If anyone can think of any counter-arguments - and in particular, any uses
ofcreate_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.
I think a documentation (as Nikic did or maybe improve it if
necessary) is enough. The deprecation tag is not about educating
people but about actually thinking about removing something at some
point. I don't see how we could remove create_function any time soon.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
On Mon, Oct 14, 2013 at 11:33 PM, Rowan Collins rowan.collins@gmail.comwrote:
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 usingcreate_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**20bd21494dhttps://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
ofcreate_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
Am 18.10.2013 11:26, schrieb Nikita Popov:
On Mon, Oct 14, 2013 at 11:33 PM, Rowan Collins rowan.collins@gmail.comwrote:
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 usingcreate_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**20bd21494dhttps://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
ofcreate_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
Hello,
shure all things can be replaced with more and verbose code. What is the
benefit of writing all this lines in contrast to one method call?
https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Helper/PhpcrCliHelper.php#L111
-1 for removing wrappers/abbreviations/and such
+1 for bugfixing
Best,
CC
Am 18.10.2013 11:26, schrieb Nikita Popov:
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).shure all things can be replaced with more and verbose code. What is the benefit of writing all this lines in contrast to one method call?
https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Helper/PhpcrCliHelper.php#L111-1 for removing wrappers/abbreviations/and such
+1 for bug fixing
I think you misunderstood Nikita's proposal.
"all these lines" can be put in a library and your code would just continue to work the way it is.
Idea is that it is trivially implemented in userland and there is no much sense to keep it in core.
--
Alexey Zakhlestin
CTO at Grids.by/you
https://github.com/indeyets
PGP key: http://indeyets.ru/alexey.zakhlestin.pgp.asc
Am 18.10.2013 12:51, schrieb Alexey Zakhlestin:
Am 18.10.2013 11:26, schrieb Nikita Popov:
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).
shure all things can be replaced with more and verbose code. What is the benefit of writing all this lines in contrast to one method call?
https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Helper/PhpcrCliHelper.php#L111-1 for removing wrappers/abbreviations/and such
+1 for bug fixingI think you misunderstood Nikita's proposal.
"all these lines" can be put in a library and your code would just continue to work the way it is.Idea is that it is trivially implemented in userland and there is no much sense to keep it in core.
It is possible to write most of the array functions in plain php with a
trivial foreach. Can't see the point.
2013/10/18 Crypto Compress cryptocompress@googlemail.com
Am 18.10.2013 12:51, schrieb Alexey Zakhlestin:
On 18.10.2013, at 14:39, Crypto Compress <cryptocompress@googlemail.com**>
wrote:
Am 18.10.2013 11:26, schrieb Nikita Popov:
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).shure all things can be replaced with more and verbose code. What is the
benefit of writing all this lines in contrast to one method call?
https://github.com/phpcr/phpcr-utils/blob/master/src/
PHPCR/Util/Console/Helper/**PhpcrCliHelper.php#L111https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Helper/PhpcrCliHelper.php#L111-1 for removing wrappers/abbreviations/and such
+1 for bug fixingI think you misunderstood Nikita's proposal.
"all these lines" can be put in a library and your code would just
continue to work the way it is.Idea is that it is trivially implemented in userland and there is no much
sense to keep it in core.It is possible to write most of the array functions in plain php with a
trivial foreach. Can't see the point.
That doesn't mean, that it was useful to include some array functions into
the core. For example I still don't really get, why it was so important to
get "array_column()" into the core, whereas it is really trivial in
PHP-userland [1]. In some cases it makes sense, for example for better
performance, but imo it doesn't make sense only for the sake of itself.
This said: Saying "but other xyz …" isn't an argument :)
Regards,
Sebastian
[1] Don't want to start a discussion about that. Just needed an example.
--
On Fri, Oct 18, 2013 at 12:39 PM, Crypto Compress <
cryptocompress@googlemail.com> wrote:
Hello,
shure all things can be replaced with more and verbose code. What is the
benefit of writing all this lines in contrast to one method call?
https://github.com/phpcr/phpcr-utils/blob/master/src/
PHPCR/Util/Console/Helper/**PhpcrCliHelper.php#L111https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Helper/PhpcrCliHelper.php#L111-1 for removing wrappers/abbreviations/and such
+1 for bugfixingBest,
CC
Could you maybe elaborate a bit on your use case there? I.e. provide some
context as to why the create_function call there is necessary and why it
can't be replaced with use of anonymous functions (and maybe also what
additional constraints there are). For people like myself that are not
familiar with the exact workings of that library.
Thanks,
Nikita
On Fri, Oct 18, 2013 at 12:39 PM, Crypto Compress <
cryptocompress@googlemail.com> wrote:Hello,
shure all things can be replaced with more and verbose code. What is the
benefit of writing all this lines in contrast to one method call?
https://github.com/phpcr/phpcr-utils/blob/master/src/
PHPCR/Util/Console/Helper/**PhpcrCliHelper.php#L111<
https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Helper/PhpcrCliHelper.php#L111-1 for removing wrappers/abbreviations/and such
+1 for bugfixingBest,
CCCould you maybe elaborate a bit on your use case there? I.e. provide some
context as to why the create_function call there is necessary and why it
can't be replaced with use of anonymous functions (and maybe also what
additional constraints there are). For people like myself that are not
familiar with the exact workings of that library.Thanks,
Nikita
I guess he is trying to say that writing a factory method for producing
callable/anonymous functions are easier with create_function than with
closures, because you call eval implicitly, instead of explicitly.
I've only skimmed through the thread, but did somebody already proposed
changing the return value of create_function to return a closure instead of
deprecating it?
That way we could keep bc and remove the ugly null-prefixed hidden function
from the global function table.
If we really we want 100% compatibility, we could even add a __toString to
the Closure object with an internal function name (similar was proposed by
Joe for anonymous functions and I listed it as a con, because not matching
the current behaviors of Closures) through which it can be called as a
string while throwing a STRICT/DEPRECATED error so people can move away
from manipulating the return value as a string, and we can remove that
behavior later on.
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
I've only skimmed through the thread, but did somebody already proposed
changing the return value of create_function to return a closure instead of
deprecating it?
I mentioned it briefly in my initial post, but felt that unless BC was
100%, it wasn't worth it, as you couldn't guarantee which of the current
behaviour people were relying on.
People can always write a version in PHP which is good enough for their
particular requirements.
If we really we want 100% compatibility, we could even add a __toString to
the Closure object with an internal function name (similar was proposed by
Joe for anonymous functions and I listed it as a con, because not matching
the current behaviors of Closures) through which it can be called as a
string while throwing a STRICT/DEPRECATED error so people can move away
from manipulating the return value as a string, and we can remove that
behavior later on.
That's an interesting idea, although I'm not sure about adding a feature
and immediately deprecating it. It seems like if closures had a
__toString, people would start to use it, so we would have to assume
that the feature was there to stay.
Another thought I had was to implement a safer version of
create_function()
under a different name, and provide a PHP-level
implementation which ran under old versions for forwards-compatibility.
You could, for instance, take an associative array of variables to close
over, which would be equivalent to the use() statement if implementing
on top of closures, and use var_export()
to interpolate into a legacy
create_function()
implementation:
usort(
$some_array,
create_eval_closure(
// args, as name only; would lack of default value support be a problem?
array('a', 'b'),
// function body, as a static string
'return strcasecmp($a[$key], $b[$key]);',
// variables to "close over"
array('key' => $key)
)
);
Basically, it would be a bit like a parameterised SQL query: you can't
actually prevent people interpolating into the strings anyway, but you
can give them a safe mechanism that means they shouldn't need to.
--
Rowan Collins
[IMSoP]
I guess he is trying to say that writing a factory method for
producing callable/anonymous functions are easier with create_function
than with closures, because you call eval implicitly, instead of
explicitly.
Exactly this historical "factory method" part is it. Thank You!
sort of documentation for the previous link:
https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Command/NodesUpdateCommand.php#L62
https://github.com/phpcr/phpcr-utils/blob/master/src/PHPCR/Util/Console/Helper/PhpcrCliHelper.php#L111
Not shure about a "safer version" with different name. Maybe breaking BC
is acceptable to some degree, if touching and refactoring this to same
codebase as closures.
Nikita Popov wrote:
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).
I can say with confidence that if this gets in to PHP, we'll integrate
BC support as above (although probably some function name like
_wp_anonymous_function_$i
), and the only real reason we still have
this is 5.2 support.
I suspect by the time 5.next rolls around, we'll be at least considering
dropping 5.2, but that of course depends on usage. At the very least,
the plugin ecosystem is starting to look towards dropping 5.2 support,
which is where the big issue will be anyway, so that's nice.
(FWIW, I always hated the create_function()
calls in WordPress anyway.)
--
Ryan McCue
<http://ryanmccue.info/
I can say with confidence that if this gets in to PHP, we'll integrate
BC support as above (although probably some function name like
_wp_anonymous_function_$i
), and the only real reason we still have
this is 5.2 support.I suspect by the time 5.next rolls around, we'll be at least considering
dropping 5.2, but that of course depends on usage. At the very least,
the plugin ecosystem is starting to look towards dropping 5.2 support,
which is where the big issue will be anyway, so that's nice.(FWIW, I always hated the
create_function()
calls in WordPress anyway.)
That's interesting to hear - I have no knowledge of the Wordpress
community and decision-making apparatus, so wasn't sure what the
reaction would be. While digging around for references, I did find this
ticket about removing a lot of the create_functions from core:
http://core.trac.wordpress.org/ticket/14424
The usages I did find in the core code were what inspired my idea for a
wrapper that took a list of variables to "close over" (like a use()
clause without the extra syntax) and used var_export()
to inject them
into the function body, as that is the pattern used in a few places.
The other interesting case I spotted was creating a function which
always returned the same string (an SQL LIMIT clause), so that it could
be registered as a filter callback. That could use an even simpler
BC-wrapper, which wouldn't need any eval() at all in >=5.3 (as long as
code was arranged such that older versions didn't try to compile it):
function lambda($return_value)
{
return function() use($return_value) { return $return_value; };
}
A fallback definition for <=5.2 would have a single var_export:
function lambda($return_value)
{
return create_function('', 'return ' . var_export($return_value,
true) . ';');
}
--
Rowan Collins
[IMSoP]
Rowan Collins wrote:
That's interesting to hear - I have no knowledge of the Wordpress
community and decision-making apparatus, so wasn't sure what the
reaction would be. While digging around for references, I did find this
ticket about removing a lot of the create_functions from core:
http://core.trac.wordpress.org/ticket/14424
For context, one of the big uses was returning static values, like
true/false/etc. We now have __return_false()/__return_empty_array()/etc
for those uses.
We also discourage it from being used for callbacks, as the
runtime-generated-naming means it's impossible to later remove it
without a variable reference to the name (ditto for closures, but people
typically only use those in development, not production).
There's only one place I can think of in the plugin community where it's
still used a fair bit (widget registration), but we can work on
discouraging that and there's a fair amount of time until the next
release in any case.
Personal +1 on this.
--
Ryan McCue
<http://ryanmccue.info/
There's only one place I can think of in the plugin community where it's
still used a fair bit (widget registration), but we can work on
discouraging that and there's a fair amount of time until the next
release in any case.
Don't forget we're only talking about deprecating, not removing it
immediately, so discouraging usage rather than eliminating it is very
much to the point.
The absolute earliest this would actually be removed would be in 5.7,
sometime in 2015. In fact, deprecating now but not expecting removal to
be possible until 5.8 / 2016 seems reasonable to me.
(Above assumes the current release sequence continues, and PHP 6 isn't
revived or something.)
--
Rowan Collins
[IMSoP]
There's only one place I can think of in the plugin community where it's
still used a fair bit (widget registration), but we can work on
discouraging that and there's a fair amount of time until the next
release in any case.Don't forget we're only talking about deprecating, not removing it
immediately, so discouraging usage rather than eliminating it is very much
to the point.The absolute earliest this would actually be removed would be in 5.7,
sometime in 2015. In fact, deprecating now but not expecting removal to be
possible until 5.8 / 2016 seems reasonable to me.
I don't think we can ever remove it in 5.x.
--
Pierre
@pierrejoye | http://www.libgd.org
The absolute earliest this would actually be removed would be in 5.7,
sometime in 2015. In fact, deprecating now but not expecting removal to be
possible until 5.8 / 2016 seems reasonable to me.
I don't think we can ever remove it in 5.x.
Is there a particular rule that separates the kind of BC breaks that are
possible between 5.x releases vs those which would require bumping the
major version? It is absolutely not the case that a program written for
PHP 5.0 can be guaranteed to run under PHP 5.5 without modification.
I thought PHP version numbers couldn't really be considered semantic
like that, ever since PHP 6 was abandoned, and major language features
from it were dropped into PHP 5.3 and 5.4. The current release policy
could plausibly continue indefinitely, with a 5.13 in 2021; "never" is a
long time...
--
Rowan Collins
[IMSoP]
On Fri, Oct 18, 2013 at 4:38 PM, Rowan Collins rowan.collins@gmail.comwrote:
On Fri, Oct 18, 2013 at 7:13 AM, Rowan Collins rowan.collins@gmail.com
wrote:The absolute earliest this would actually be removed would be in 5.7,
sometime in 2015. In fact, deprecating now but not expecting removal to
be
possible until 5.8 / 2016 seems reasonable to me.I don't think we can ever remove it in 5.x.
Is there a particular rule that separates the kind of BC breaks that are
possible between 5.x releases vs those which would require bumping the
major version? It is absolutely not the case that a program written for PHP
5.0 can be guaranteed to run under PHP 5.5 without modification.I thought PHP version numbers couldn't really be considered semantic like
that, ever since PHP 6 was abandoned, and major language features from it
were dropped into PHP 5.3 and 5.4. The current release policy could
plausibly continue indefinitely, with a 5.13 in 2021; "never" is a long
time...
shouldn't really happen if you strictly follow the "new" release process
rfc was accepted: https://wiki.php.net/rfc/releaseprocess , unfortunatelly
it seems that there are some cases, when this can happen (some bug fixes,
but the biggest offender was dropping deprecated features for 5.4.0 which
were already removed in the 6.0 branch), but if you check out
http://hu1.php.net/manual/en/migration55.incompatible.php you can see that
the actual intentional BC breaks was really small, the only non bugfix BC
break was removing the php logo urls, which was never meant to be a public
api, but to be used by phpinfo()
.
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
shouldn't really happen if you strictly follow the "new" release
process rfc was accepted: https://wiki.php.net/rfc/releaseprocess ,
unfortunatelly it seems that there are some cases, when this can
happen (some bug fixes, but the biggest offender was dropping
deprecated features for 5.4.0 which were already removed in the 6.0
branch), but if you check out
http://hu1.php.net/manual/en/migration55.incompatible.php you can see
that the actual intentional BC breaks was really small, the only non
bugfix BC break was removing the php logo urls, which was never meant
to be a public api, but to be used byphpinfo()
.
Ah, I see. I guess it was the slew of changes in 5.3 and 5.4 which made
it seem like this wasn't the case, because they would collectively have
been 6.0. So the aim is that a script made to work on PHP 5.4 will now
be guaranteed to run on any version <6, although some required modules
might have moved to PECL?
As a user, it is certainly not obvious that features discussed as being
removed "soon" will only actually disappear once there is a 6.0, because
there doesn't seem to be any reason to expect PHP 6 to be "soon". Unless
a release within the next few years is numbered 6.0 (or something else
- simply to clean up the deprecated functionality, without actually
including major changes like the Unicode string concept.
--
Rowan Collins
[IMSoP]