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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.