cvs: ZendEngine2 / zend_closures.c /tests closure_013.phpt closure_014.phpt
"Dmitry Stogov" <[email protected]>
| Newsgroups | gmane.comp.php.cvs.zend |
|---|---|
| Message-ID | <cvsdmitry1215533708@cvsserver> |
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
--
Zend Engine CVS Mailing List (http://cvs.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php