]> granicus.if.org Git - php/commitdiff
Fixed is_callable() to support closures and return appropriate function name
authorDmitry Stogov <dmitry@php.net>
Mon, 14 Jul 2008 12:18:23 +0000 (12:18 +0000)
committerDmitry Stogov <dmitry@php.net>
Mon, 14 Jul 2008 12:18:23 +0000 (12:18 +0000)
Zend/tests/closure_016.phpt [new file with mode: 0755]
Zend/zend_API.c
Zend/zend_closures.c
Zend/zend_compile.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/closure_016.phpt b/Zend/tests/closure_016.phpt
new file mode 100755 (executable)
index 0000000..ae00365
--- /dev/null
@@ -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
index 68f0c7880ce1f2f72841067888f22480377ff197..358feff3c925022e90c2a4d6619a61306cf41ca4 100644 (file)
@@ -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;
                        }
index 5ed979cc62766d8fe2574d98d03c1c20a5cd284c..30187a8fc758749a73167adb35a14de75986a309 100644 (file)
@@ -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;
index 5546e2a0da8ec99e26473179bb47c661ea19d8f2..7a8a2c3af444b12a91c17965bce3b15444464f8b 100644 (file)
@@ -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);
 
index a907f50146bac1c5aabd03bd6af0c864bbe65540..6c35cd9b5de872d11f84ea05097adcf1b1a34d69 100644 (file)
@@ -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) {
index 3026f4555b5433fc0b2726f460d56d710e005ae9..d928c1ae26c0da25d0d1fb7d085936be44b8e8af 100644 (file)
@@ -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) {