cvs: ZendEngine2 / zend_closures.c /tests closure_013.phpt closure_014.phpt

From: Date: Tue, 08 Jul 2008 16:15:08 +0000
Subject: cvs: ZendEngine2 / zend_closures.c /tests closure_013.phpt closure_014.phpt
Groups: php.zend-engine.cvs 
Request: Send a blank email to php-zend-engine-cvs+get-6871@lists.php.net to get a copy of this message
dmitry Tue Jul 8 16:15:08 2008 UTC Added files: /ZendEngine2/tests closure_013.phpt closure_014.phpt Modified files: /ZendEngine2 zend_closures.c Log: Closure::__invoke() is fixed to support references http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_closures.c?r1=1.1&r2=1.2&diff_format=u Index: ZendEngine2/zend_closures.c diff -u ZendEngine2/zend_closures.c:1.1 ZendEngine2/zend_closures.c:1.2 --- ZendEngine2/zend_closures.c:1.1 Tue Jul 8 07:05:03 2008 +++ ZendEngine2/zend_closures.c Tue Jul 8 16:15:08 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_closures.c,v 1.1 2008/07/08 07:05:03 dmitry Exp $ */ +/* $Id: zend_closures.c,v 1.2 2008/07/08 16:15:08 dmitry Exp $ */ #include "zend.h" #include "zend_API.h" @@ -26,10 +26,13 @@ #include "zend_objects_API.h" #include "zend_globals.h" +#define ZEND_INVOKE_FUNC_NAME "__invoke" + typedef struct _zend_closure { zend_object std; zend_function func; zval *this_ptr; + zend_function *invoke; } zend_closure; static zend_class_entry *zend_ce_closure; @@ -47,28 +50,25 @@ RETURN_FALSE; } - if (!return_value_ptr) { - return_value_ptr = &closure_result_ptr; - } - - if (call_user_function_ex(CG(function_table), NULL, this_ptr, return_value_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) { + if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) { efree(arguments); RETURN_FALSE; } efree(arguments); if (closure_result_ptr) { - RETVAL_ZVAL(closure_result_ptr, 1, 1); + if (Z_ISREF_P(closure_result_ptr) && return_value_ptr) { + if (return_value) { + zval_ptr_dtor(&return_value); + } + *return_value_ptr = closure_result_ptr; + } else { + RETVAL_ZVAL(closure_result_ptr, 1, 1); + } } } /* }}} */ -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"); @@ -103,6 +103,39 @@ } /* }}} */ +static zend_function *zend_closure_get_method(zval **object_ptr, zstr method_name, int method_len TSRMLS_DC) /* {{{ */ +{ + unsigned int lc_name_len; + zstr lc_name; + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; + + /* Create a zend_copy_str_tolower(dest, src, src_length); */ + lc_name = zend_u_str_case_fold(type, method_name, method_len, 1, &lc_name_len); + if ((lc_name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && + (ZEND_U_EQUAL(type, lc_name, lc_name_len, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) { + zend_closure *closure = (zend_closure *)zend_object_store_get_object(*object_ptr TSRMLS_CC); + + if (!closure->invoke) { + closure->invoke = (zend_function*)emalloc(sizeof(zend_function)); + closure->invoke->common = closure->func.common; + closure->invoke->type = ZEND_INTERNAL_FUNCTION; + closure->invoke->internal_function.handler = ZEND_MN(Closure___invoke); + closure->invoke->internal_function.module = 0; + closure->invoke->internal_function.scope = zend_ce_closure; + if (UG(unicode)) { + closure->invoke->internal_function.function_name.u = USTR_MAKE(ZEND_INVOKE_FUNC_NAME); + } else { + closure->invoke->internal_function.function_name.s = ZEND_INVOKE_FUNC_NAME; + } + } + efree(lc_name.v); + return (zend_function *)closure->invoke; + } + efree(lc_name.v); + return NULL; +} +/* }}} */ + static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */ { zend_closure *closure = (zend_closure *)object; @@ -124,6 +157,13 @@ zval_ptr_dtor(&closure->this_ptr); } + if (closure->invoke) { + if (UG(unicode)) { + efree(closure->invoke->internal_function.function_name.u); + } + efree(closure->invoke); + } + efree(closure); } /* }}} */ @@ -149,13 +189,14 @@ { zend_class_entry ce; - INIT_CLASS_ENTRY(ce, "Closure", closure_functions); + INIT_CLASS_ENTRY(ce, "Closure", NULL); 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; memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); closure_handlers.get_constructor = zend_closure_get_constructor; + closure_handlers.get_method = zend_closure_get_method; closure_handlers.compare_objects = zend_closure_compare_objects; closure_handlers.cast_object = zend_closure_cast_object_tostring; closure_handlers.clone_obj = NULL; @@ -169,7 +210,6 @@ TSRMLS_FETCH(); if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) { - TSRMLS_FETCH(); is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF; if (!EG(active_symbol_table)) { @@ -243,9 +283,9 @@ zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; if (utype == IS_UNICODE) { - key.u = USTR_MAKE("__invoke"); + key.u = USTR_MAKE(ZEND_INVOKE_FUNC_NAME); } else { - key.s = "__invoke"; + key.s = ZEND_INVOKE_FUNC_NAME; } if (Z_TYPE_P(obj) == IS_OBJECT) { @@ -276,7 +316,7 @@ efree(key.u); } return SUCCESS; - } else if (zend_u_hash_find(&ce->function_table, utype, key, sizeof("__invoke"), (void**)fptr_ptr) == SUCCESS) { + } else if (zend_u_hash_find(&ce->function_table, utype, key, sizeof(ZEND_INVOKE_FUNC_NAME), (void**)fptr_ptr) == SUCCESS) { *ce_ptr = ce; if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) { if (zobj_ptr) { http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_013.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_013.phpt +++ ZendEngine2/tests/closure_013.phpt --TEST-- Closure 013: __invoke() on temporary result --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php class Foo { function __invoke() { echo "Hello World!\n"; } } function foo() { return function() { echo "Hello World!\n"; }; } $test = new Foo; $test->__invoke(); $test = foo(); $test->__invoke(); $test = foo()->__invoke(); ?> --EXPECT-- Hello World! Hello World! Hello World! http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_014.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_014.phpt +++ ZendEngine2/tests/closure_014.phpt --TEST-- Closure 014: return by value/reference --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php class C1 { function __invoke() { return 0; } } class C2 { function &__invoke(&$a) { return $a; } } class C3 { function __invoke() { } } $x = new C1(); var_dump($x()); var_dump($x->__invoke()); $x(); $x->__invoke(); $x = function() { return 0; }; var_dump($x()); var_dump($x->__invoke()); $x(); $x->__invoke(); $x = new C2(); $a = $b = $c = $d = 1; $e =& $x($a); $e = 2; var_dump($a); $e =& $x->__invoke($b); $e = 3; var_dump($b); $x($b); $x->__invoke($b); $x = function & (&$a) { return $a; }; $e =& $x($c); $e = 4; var_dump($c); $e =& $x->__invoke($d); $e = 5; var_dump($d); $x($d); $x->__invoke($d); $x = new C3(); var_dump($x()); var_dump($x->__invoke()); $x(); $x->__invoke(); $x = function() { }; var_dump($x()); var_dump($x->__invoke()); $x(); $x->__invoke(); ?> --EXPECT-- int(0) int(0) int(0) int(0) int(2) int(3) int(4) int(5) NULL NULL NULL NULL

« previous php.zend-engine.cvs (#6871) next »