From 16fa2abc2071fb0b05d61896f2e487289398f0cd Mon Sep 17 00:00:00 2001 From: Adam Saponara Date: Fri, 10 Feb 2017 23:58:25 -0500 Subject: [PATCH 1/2] Fix `is_callable()` `$callable_name` for anon class methods --- .../general_functions/is_callable_anon.phpt | 22 +++++++++++++++++++ ext/standard/type.c | 7 ++++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/general_functions/is_callable_anon.phpt diff --git a/ext/standard/tests/general_functions/is_callable_anon.phpt b/ext/standard/tests/general_functions/is_callable_anon.phpt new file mode 100644 index 0000000000000..635f2a04ab29c --- /dev/null +++ b/ext/standard/tests/general_functions/is_callable_anon.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test is_callable() function : usage variations - anonymous class method +--FILE-- + +--EXPECT-- +nice diff --git a/ext/standard/type.c b/ext/standard/type.c index 9e5c154f237f3..c715356f3335c 100644 --- a/ext/standard/type.c +++ b/ext/standard/type.c @@ -409,8 +409,11 @@ PHP_FUNCTION(is_callable) if (ZEND_NUM_ARGS() > 2) { retval = zend_is_callable_ex(var, NULL, check_flags, &name, NULL, &error); zval_dtor(callable_name); - //??? is it necessary to be consistent with old PHP ("\0" support) - if (UNEXPECTED(ZSTR_LEN(name) != strlen(ZSTR_VAL(name)))) { + if (retval && check_flags == 0) { + // `var` is callable and actually exists. Return `name` as-is (including + // any null-chars) so that `call_user_func($callable_name)` works. + ZVAL_STR(callable_name, name); + } else if (UNEXPECTED(ZSTR_LEN(name) != strlen(ZSTR_VAL(name)))) { ZVAL_STRINGL(callable_name, ZSTR_VAL(name), strlen(ZSTR_VAL(name))); zend_string_release(name); } else { From 22eda35dd2d745269f23208d596133581c21d665 Mon Sep 17 00:00:00 2001 From: Adam Saponara Date: Sat, 11 Feb 2017 14:14:20 -0500 Subject: [PATCH 2/2] Always return full callable_name in is_callable --- .../is_callable_variation1.phpt | 79 +++++++++---------- ext/standard/type.c | 11 +-- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/ext/standard/tests/general_functions/is_callable_variation1.phpt b/ext/standard/tests/general_functions/is_callable_variation1.phpt index cfc14bbd9c685..1d3bca601148e 100644 --- a/ext/standard/tests/general_functions/is_callable_variation1.phpt +++ b/ext/standard/tests/general_functions/is_callable_variation1.phpt @@ -21,10 +21,10 @@ function check_iscallable( $functions ) { var_dump( is_callable($func) ); //given only $var argument var_dump( is_callable($func, TRUE) ); //given $var and $syntax argument var_dump( is_callable($func, TRUE, $callable_name) ); - echo $callable_name, "\n"; + echo json_encode($callable_name) . "\n"; var_dump( is_callable($func, FALSE) ); //given $var and $syntax argument var_dump( is_callable($func, FALSE, $callable_name) ); - echo $callable_name, "\n"; + echo json_encode($callable_name) . "\n"; $counter++; } } @@ -59,150 +59,149 @@ check_iscallable($undef_functions); ?> ===DONE=== ---EXPECTF-- *** Testing is_callable() on undefined functions *** -- Iteration 1 -- bool(false) bool(true) bool(true) - +"" bool(false) bool(false) - +"" -- Iteration 2 -- bool(false) bool(true) bool(true) - +"" bool(false) bool(false) - +"" -- Iteration 3 -- bool(false) bool(true) bool(true) - +" " bool(false) bool(false) - +" " -- Iteration 4 -- bool(false) bool(true) bool(true) - +" " bool(false) bool(false) - +" " -- Iteration 5 -- bool(false) bool(true) bool(true) -12356 +"12356" bool(false) bool(false) -12356 +"12356" -- Iteration 6 -- bool(false) bool(true) bool(true) - +"\u0000" bool(false) bool(false) - +"\u0000" -- Iteration 7 -- bool(false) bool(true) bool(true) -\0 +"\\0" bool(false) bool(false) -\0 +"\\0" -- Iteration 8 -- bool(false) bool(true) bool(true) -hello world +"hello world" bool(false) bool(false) -hello world +"hello world" -- Iteration 9 -- bool(false) bool(true) bool(true) -hello world +"hello world" bool(false) bool(false) -hello world +"hello world" -- Iteration 10 -- bool(false) bool(true) bool(true) -welcome +"welcome\u0000" bool(false) bool(false) -welcome +"welcome\u0000" -- Iteration 11 -- bool(false) bool(true) bool(true) -welcome\0 +"welcome\\0" bool(false) bool(false) -welcome\0 +"welcome\\0" -- Iteration 12 -- bool(false) bool(true) bool(true) -==%%%***$$$@@@!! +"==%%%***$$$@@@!!" bool(false) bool(false) -==%%%***$$$@@@!! +"==%%%***$$$@@@!!" -- Iteration 13 -- bool(false) bool(true) bool(true) -false +"false" bool(false) bool(false) -false +"false" -- Iteration 14 -- bool(false) bool(true) bool(true) -8 +"8" bool(false) bool(false) -8 +"8" -- Iteration 15 -- bool(false) bool(true) bool(true) -\t +"\\t" bool(false) bool(false) -\t +"\\t" -- Iteration 16 -- bool(false) bool(true) bool(true) -\007 +"\\007" bool(false) bool(false) -\007 +"\\007" -- Iteration 17 -- bool(false) bool(true) bool(true) -123 +"123" bool(false) bool(false) -123 +"123" -- Iteration 18 -- bool(false) bool(true) bool(true) -echo() +"echo()" bool(false) bool(false) -echo() -===DONE=== \ No newline at end of file +"echo()" +===DONE=== diff --git a/ext/standard/type.c b/ext/standard/type.c index c715356f3335c..a8000504628f2 100644 --- a/ext/standard/type.c +++ b/ext/standard/type.c @@ -409,16 +409,7 @@ PHP_FUNCTION(is_callable) if (ZEND_NUM_ARGS() > 2) { retval = zend_is_callable_ex(var, NULL, check_flags, &name, NULL, &error); zval_dtor(callable_name); - if (retval && check_flags == 0) { - // `var` is callable and actually exists. Return `name` as-is (including - // any null-chars) so that `call_user_func($callable_name)` works. - ZVAL_STR(callable_name, name); - } else if (UNEXPECTED(ZSTR_LEN(name) != strlen(ZSTR_VAL(name)))) { - ZVAL_STRINGL(callable_name, ZSTR_VAL(name), strlen(ZSTR_VAL(name))); - zend_string_release(name); - } else { - ZVAL_STR(callable_name, name); - } + ZVAL_STR(callable_name, name); } else { retval = zend_is_callable_ex(var, NULL, check_flags, NULL, NULL, &error); }