mirror of
https://github.com/php/php-src.git
synced 2025-08-16 22:18:50 +02:00
Fixed is_callable() to support closures and return appropriate function name
This commit is contained in:
parent
bc12bc69aa
commit
0fa7fedfde
6 changed files with 67 additions and 6 deletions
51
Zend/tests/closure_016.phpt
Executable file
51
Zend/tests/closure_016.phpt
Executable file
|
@ -0,0 +1,51 @@
|
|||
--TEST--
|
||||
Closure 016: closures and is_callable()
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
function __invoke() {
|
||||
echo "Hello World!\n";
|
||||
}
|
||||
}
|
||||
|
||||
function foo() {
|
||||
return function() {
|
||||
echo "Hello World!\n";
|
||||
};
|
||||
}
|
||||
$test = new Foo;
|
||||
var_dump(is_callable($test, true, $name));
|
||||
echo $name."\n";
|
||||
var_dump(is_callable($test, false, $name));
|
||||
echo $name."\n";
|
||||
var_dump(is_callable(array($test,"__invoke"), true, $name));
|
||||
echo $name."\n";
|
||||
var_dump(is_callable(array($test,"__invoke"), false, $name));
|
||||
echo $name."\n";
|
||||
$test = foo();
|
||||
var_dump(is_callable($test, true, $name));
|
||||
echo $name."\n";
|
||||
var_dump(is_callable($test, false, $name));
|
||||
echo $name."\n";
|
||||
var_dump(is_callable(array($test,"__invoke"), true, $name));
|
||||
echo $name."\n";
|
||||
var_dump(is_callable(array($test,"__invoke"), false, $name));
|
||||
echo $name."\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
Foo::__invoke
|
||||
bool(true)
|
||||
Foo::__invoke
|
||||
bool(true)
|
||||
Foo::__invoke
|
||||
bool(true)
|
||||
Foo::__invoke
|
||||
bool(true)
|
||||
Closure::__invoke
|
||||
bool(true)
|
||||
Closure::__invoke
|
||||
bool(true)
|
||||
Closure::__invoke
|
||||
bool(true)
|
||||
Closure::__invoke
|
|
@ -2619,8 +2619,12 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
|
|||
case IS_OBJECT:
|
||||
if (zend_get_closure(callable, ce_ptr, fptr_ptr, NULL, zobj_ptr_ptr TSRMLS_CC) == SUCCESS) {
|
||||
if (callable_name) {
|
||||
*callable_name_len = strlen((*fptr_ptr)->common.function_name);
|
||||
*callable_name = estrndup((*fptr_ptr)->common.function_name, *callable_name_len);
|
||||
zend_class_entry *ce = Z_OBJCE_P(callable); /* TBFixed: what if it's overloaded? */
|
||||
|
||||
*callable_name_len = ce->name_length + sizeof("::__invoke") - 1;
|
||||
*callable_name = emalloc(*callable_name_len + 1);
|
||||
memcpy(*callable_name, ce->name, ce->name_length);
|
||||
memcpy((*callable_name) + ce->name_length, "::__invoke", sizeof("::__invoke"));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,12 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
const static zend_function_entry closure_functions[] = { /* {{{ */
|
||||
ZEND_ME(Closure, __invoke, NULL, 0)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_error(E_ERROR, "Instantiation of 'Closure' is not allowed");
|
||||
|
@ -181,7 +187,7 @@ void zend_register_closure_ce(TSRMLS_D) /* {{{ */
|
|||
{
|
||||
zend_class_entry ce;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "Closure", NULL);
|
||||
INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
|
||||
zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
|
||||
zend_ce_closure->create_object = zend_closure_new;
|
||||
|
|
|
@ -1409,7 +1409,7 @@ void zend_do_begin_lambda_function_declaration(znode *result, znode *function_to
|
|||
zend_op *current_op;
|
||||
|
||||
function_name.op_type = IS_CONST;
|
||||
ZVAL_STRINGL(&function_name.u.constant, "lambda", sizeof("lambda")-1, 1);
|
||||
ZVAL_STRINGL(&function_name.u.constant, "", sizeof("")-1, 1);
|
||||
|
||||
zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC);
|
||||
|
||||
|
|
|
@ -4339,7 +4339,7 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
|
|||
ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, CONST)
|
||||
{
|
||||
zend_op *opline = EX(opline);
|
||||
zend_op_array *op_array;
|
||||
zend_function *op_array;
|
||||
|
||||
if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), Z_LVAL(opline->op2.u.constant), (void *) &op_array) == FAILURE ||
|
||||
op_array->type != ZEND_USER_FUNCTION) {
|
||||
|
|
|
@ -2914,7 +2914,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCOD
|
|||
static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
zend_op *opline = EX(opline);
|
||||
zend_op_array *op_array;
|
||||
zend_function *op_array;
|
||||
|
||||
if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), Z_LVAL(opline->op2.u.constant), (void *) &op_array) == FAILURE ||
|
||||
op_array->type != ZEND_USER_FUNCTION) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue