Bug #68026 [Nab]: create_function() fails
| From: | johannes@php.net | Date: | Thu, 18 Sep 2014 13:54:08 +0000 |
| Subject: | Bug #68026 [Nab]: create_function() fails | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-187589@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=68026&edit=1
ID: 68026
Updated by: johannes@php.net
Reported by: jmichae3 at yahoo dot com
Summary: create_function() fails
Status: Not a bug
Type: Bug
Package: Scripting Engine problem
Operating System: Windows 7 pro x64 sp1
PHP Version: 5.5.16
Block user comment: N
Private report: N
New Comment:
Please go to a support forum. There is no bug here. Variable variables, create_function() and
is_callable() work as they should.
Previous Comments:
------------------------------------------------------------------------
[2014-09-18 11:11:51] jmicha3 at yahoo dot com
"Your code to test function creation should be
!is_callable(${'is'.$AcctTypes[$i].'file'})"
this does not match what is given in the example in the documentation (although it works somehow
regardless of the example).
http://php.net/manual/en/function.is-callable.php
this is exacerbated by another lack of definition or proper link for the linked term
"callable" at http://php.net/manual/en/language.types.callable.php
which leads to the top of the same page and gives no definition for the "callable" type
hint. I have no clue what a type hint is. so I put "type hint" in the search box, and I
got "not found".
<?php
$a=array('admin','user','moderator');
for ($i=0; $i<count($a); $i++) {
${'abc'.$a[$i].'file'}=$a[$i] . $i;
if (isset(${'abc'.$a[$i].'file'})) {
echo
'abc'.$a[$i].'file'."=".${'abc'.$a[$i].'file'}."\n";
}
}
echo ${'abcadminfile'}."\n";
?>
D:\prj\test\php\varvar>php varvar.php
abcadminfile=admin0
abcuserfile=user1
abcmoderatorfile=moderator2
admin0
D:\prj\test\php\varvar>
https://bugs.php.net/bug.php?id=68026
variable variables *do* in fact work, and there is no conflict with existing function names etc.
<?php
$s='moderator';
$funcbody =' return ((strpos($filepath,"/admin/") !== false';
$funcbody.= ' && strpos($filepath,"/admin/") <=3));'; //is this in
the /admin/ or /moderator/ etc directory off root?
$isadminfile=create_function('$filepath',$funcbody);
${'is'.$s.'file'}=create_function('$filepath',$funcbody);
echo
"isset(\$".'isadminfile'.")=".(isset($isadminfile)?"true\n":"false\n");
echo
"function_exists(".'isadminfile'.")=".(function_exists('isadminfile')?"true\n":"false\n");
echo
"is_callable(\${".'isadminfile'."})=".(is_callable(${'isadminfile'})?"true\n":"false\n");
echo "\n";
echo
"isset(\${'is'.\$s.'file'.})=".(isset(${'is'.$s.'file'})?"true\n":"false\n");
echo
"function_exists('is'.\$s.'file')=".(function_exists('is'.$s.'file')?"true\n":"false\n");
echo
"is_callable(\${'is'.\$s.'file'})=".(is_callable(${'is'.$s.'file'})?"true\n":"false\n");
?>
Wed 09/17/2014 22:40:34.28|D:\prj\test\php\create_function||>PHP CF.PHP
isset($isadminfile)=true
function_exists(isadminfile)=false
is_callable(${isadminfile})=true
isset(${'is'.$s.'file'.})=true
function_exists('is'.$s.'file')=false
is_callable(${'is'.$s.'file'})=true
Wed 09/17/2014 22:40:49.20|D:\prj\test\php\create_function||>
unfortunately, I have just found a bug in function_exists(). instead of taking a string which is the
function name, it takes the lambda function body itself. look at the results above. this does not
match the manual's description and example for this argument.
http://php.net/manual/en/function.function-exists.php
strangely enough, when I try function_exists() on a php built-in function instead of a lambda
function, it works.
let's try a built-in function:
<?php
var_dump(function_exists('create_function'));
?>
D:\prj\test\php\function_exists>php fe.php
bool(true)
D:\prj\test\php\function_exists>
so the failure bug in function_exists only happens under the condition where a lambda function is
used.
------------------------------------------------------------------------
[2014-09-17 10:35:34] johannes@php.net
You assume $isAdminfile = create_function(...); to create a function isAdminfile as previously said
and written in the docs this not the case. It creates a function called \0lambda_1 and returns that
name. A way to fix your code was provided above.
Aside from that - even if features exist there might be tools which haven proven to be better.
create_function() takes code as a string parameter which makes reading and writing hard and also
inefficient. The documentation explicitly mentions closures. Just from the code I don't see the
reason for this either, though as this could be a normal function with the type as parameter ... but
there might be a valid reason not to do that.
It might also be worth for you to look at foreach and explode() to write more efficient code. But as
said: This is no support forum. create_function() works like expected and documented. With the
suggested fix your code gave the expected result.
------------------------------------------------------------------------
[2014-09-17 09:10:14] jmichae3 at yahoo dot com
Your code to test function creation should be
!is_callable(${'is'.$AcctTypes[$i].'file'})
But please, do a favor for everyone who has to deal with your code:
1. Stop using globals
2. Don't use variable variables
3. Don't dynamically create important functions
is_callable():
your syntax is wrong according to the manual, and anyway it fails when I use it:
"Stop using globals":
no law against using globals. unless the global keyword is only for making an outside variable
visible inside a function, in which case you need to say that in the manual, so that's a
documentation bug, because that's not stated. I wanted to declare my vars with global-scope and
have it visible all throughout my code. they are really important variables.
"Don't dynamically create important functions":
in other words, don't rely on the spec or any functions in the manual, throw the manual away.
if a given function is documented as being there, php.net is not really giving it to you, it's
just virtual? do you realize what you just said and how backwards that sounds?
ERROR: lamba function isadminfile() doesn't exist.
ERROR: lamba function name isadminfile is not callable.
ERROR: lamba function ispaidblsfile() doesn't exist.
ERROR: lamba function name ispaidblsfile is not callable.
ERROR: lamba function ispaidmusicfile() doesn't exist.
ERROR: lamba function name ispaidmusicfile is not callable.
ERROR: lamba function isuserfile() doesn't exist.
ERROR: lamba function name isuserfile is not callable.
so you are basically saying stop writing code period? I am just following spec. everything I am
trying are things the manual says I should be able to do, like variable variables etc. I fully
expect them to work. if it doesn't work, then fix the bugs please. found 2 PHP bugs already
just trying to convert my code to a new way of doing things.
------------------------------------------------------------------------
[2014-09-17 08:25:44] requinix@php.net
This is not the place for an in-depth explanation of why your code is wrong. Please re-read what I
said, or try an online forum or mailing list.
http://php.net/support.php
------------------------------------------------------------------------
[2014-09-17 08:09:50] jmichae3 at yahoo dot com
you dismissed the bug out of hand, it's still valid.
for ($i=0; $i < count($AcctTypes); $i++) {
//global ${'is'.$AcctTypes[$i].'file'};
//in our web site, we detect if the /admin/ directory
$funcbody =' return ((strpos($filepath,"/'.$AcctTypes[$i].'/") !==
false';
$funcbody.= ' && strpos($filepath,"/'.$AcctTypes[$i].'/")
<=3));'; //is this in the /admin/ or /moderator/ etc directory off root?
//create the function from the function body in $funcbody with name in $funcname
${'is'.$AcctTypes[$i].'file'}=create_function('$filepath',
$funcbody);
//aggregate any failures so we can see what's wrong and fix it
$anyError=false;
if (!isset(${'is'.$AcctTypes[$i].'file'})) {
echo "ERROR: lambda function name variable
".'is'.$AcctTypes[$i].'file'." failed isset().\n";
$anyError=true;
}
if (!function_exists('is'.$AcctTypes[$i].'file')) {
echo "ERROR: lamba function
".'is'.$AcctTypes[$i].'file'."() doesn't exist.\n";
$anyError=true;
}
}
if ($anyError) {
die("----please fix code.\n");
}
output:
ERROR: lamba function isadminfile() doesn't exist.
ERROR: lamba function ispaidblsfile() doesn't exist.
ERROR: lamba function ispaidmusicfile() doesn't exist.
ERROR: lamba function isuserfile() doesn't exist.
----please fix code.
regardless of whether it contained a functoin name or not, its contents would have been replaced
with a function (supposedly) by the call to create_function, would it not?
what I needed was to make a variable with a variable name (which I could base on a for loop to make
a number of functions) that is also a function name. but this is consistently failing.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=68026
--
Edit this bug report at https://bugs.php.net/bug.php?id=68026&edit=1