summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xZend/tests/closure_033.phpt28
-rwxr-xr-xZend/tests/closure_034.phpt233
-rw-r--r--Zend/zend_closures.c13
-rw-r--r--Zend/zend_closures.h1
-rw-r--r--Zend/zend_object_handlers.c4
5 files changed, 278 insertions, 1 deletions
diff --git a/Zend/tests/closure_033.phpt b/Zend/tests/closure_033.phpt
new file mode 100755
index 0000000000..f6510066bb
--- /dev/null
+++ b/Zend/tests/closure_033.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Closure 033: Dynamic closure property and private function
+--FILE--
+<?php
+
+class Test {
+ public $func;
+ function __construct() {
+ $this->func = function() {
+ echo __METHOD__ . "()\n";
+ };
+ }
+ private function func() {
+ echo __METHOD__ . "()\n";
+ }
+}
+
+$o = new Test;
+$f = $o->func;
+$f();
+$o->func();
+
+?>
+===DONE===
+--EXPECTF--
+Test::{closure}()
+
+Fatal error: Call to private method Test::func() from context '' in %sclosure_033.php on line %d
diff --git a/Zend/tests/closure_034.phpt b/Zend/tests/closure_034.phpt
new file mode 100755
index 0000000000..c919671cd0
--- /dev/null
+++ b/Zend/tests/closure_034.phpt
@@ -0,0 +1,233 @@
+--TEST--
+Closure 034: var_dump() of a Closure
+--FILE--
+<?php
+
+$outer = 25;
+
+class Test {
+ public $func1;
+ public $var = 42;
+ function __construct() {
+ global $outer;
+ $this->func1 = function($param, $other = "default") use ($outer) {
+ };
+ }
+}
+
+$o = new Test;
+var_dump($o->func1);
+
+$o->func2 = function($param, $other = "default") use ($outer) {
+};
+
+var_dump($o->func2);
+
+$func3 = function($param, $other = "default") use ($outer) {
+};
+
+var_dump($func3);
+
+?>
+===DONE===
+--EXPECTF--
+object(Closure)#%d (3) {
+ ["this"]=>
+ object(Test)#%d (2) {
+ ["func1"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ object(Test)#%d (2) {
+ ["func1"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ *RECURSION*
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ ["var"]=>
+ int(42)
+ }
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ ["var"]=>
+ int(42)
+ }
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+}
+object(Closure)#%d (3) {
+ ["this"]=>
+ object(Test)#%d (3) {
+ ["func1"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ object(Test)#%d (3) {
+ ["func1"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ *RECURSION*
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ ["var"]=>
+ int(42)
+ ["func2"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ *RECURSION*
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ &int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ }
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ ["var"]=>
+ int(42)
+ ["func2"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ object(Test)#%d (3) {
+ ["func1"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ *RECURSION*
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ ["var"]=>
+ int(42)
+ ["func2"]=>
+ object(Closure)#%d (3) {
+ ["this"]=>
+ *RECURSION*
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ &int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ }
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ &int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+ }
+ }
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ &int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+}
+object(Closure)#%d (3) {
+ ["this"]=>
+ NULL
+ ["static"]=>
+ array(1) {
+ ["outer"]=>
+ int(25)
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$param"]=>
+ string(10) "<required>"
+ ["$other"]=>
+ string(10) "<optional>"
+ }
+}
+===DONE===
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index f2e5024f41..1f65e11668 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -118,6 +118,17 @@ ZEND_API zval* zend_get_closure_this_ptr(zval *obj TSRMLS_DC) /* {{{ */
}
/* }}} */
+ZEND_API zval* zend_closure_copy(zval *closure_obj, zval *this_ptr TSRMLS_DC) /* {{{ */
+{
+ zend_closure *closure;
+
+ zval_copy_ctor(closure_obj);
+ closure = (zend_closure *)zend_object_store_get_object(closure_obj TSRMLS_CC);
+ closure->this_ptr = this_ptr;
+ return closure_obj;
+}
+/* }}} */
+
static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */
{
char *lc_name;
@@ -238,7 +249,7 @@ int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function
}
/* }}} */
-ZEND_API HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
+static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
{
zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
HashTable *rv;
diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h
index c326e329c4..006af06671 100644
--- a/Zend/zend_closures.h
+++ b/Zend/zend_closures.h
@@ -35,6 +35,7 @@ ZEND_API int zend_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_functio
ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC);
ZEND_API const zend_function *zend_get_closure_method_def(zval *obj TSRMLS_DC);
ZEND_API zval* zend_get_closure_this_ptr(zval *obj TSRMLS_DC);
+ZEND_API zval* zend_closure_copy(zval *closure, zval *this_ptr TSRMLS_DC);
END_EXTERN_C()
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 57f7d3d2e3..27f1461a1e 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -405,6 +405,10 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM
member = tmp_member;
}
+ if (value && Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ce_closure && zend_get_closure_this_ptr(value TSRMLS_CC) != object) {
+ value = zend_closure_copy(value, object TSRMLS_CC);
+ }
+
property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__set != NULL) TSRMLS_CC);
if (property_info && zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) {