diff --git a/Zend/tests/closure_033.phpt b/Zend/tests/closure_033.phpt new file mode 100755 index 00000000000..f6510066bbc --- /dev/null +++ b/Zend/tests/closure_033.phpt @@ -0,0 +1,28 @@ +--TEST-- +Closure 033: Dynamic closure property and private function +--FILE-- +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 00000000000..c919671cd04 --- /dev/null +++ b/Zend/tests/closure_034.phpt @@ -0,0 +1,233 @@ +--TEST-- +Closure 034: var_dump() of a Closure +--FILE-- +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) "" + ["$other"]=> + string(10) "" + } + } + ["var"]=> + int(42) + } + ["static"]=> + array(1) { + ["outer"]=> + int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } + } + ["var"]=> + int(42) + } + ["static"]=> + array(1) { + ["outer"]=> + int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } +} +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) "" + ["$other"]=> + string(10) "" + } + } + ["var"]=> + int(42) + ["func2"]=> + object(Closure)#%d (3) { + ["this"]=> + *RECURSION* + ["static"]=> + array(1) { + ["outer"]=> + &int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } + } + } + ["static"]=> + array(1) { + ["outer"]=> + int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } + } + ["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) "" + ["$other"]=> + string(10) "" + } + } + ["var"]=> + int(42) + ["func2"]=> + object(Closure)#%d (3) { + ["this"]=> + *RECURSION* + ["static"]=> + array(1) { + ["outer"]=> + &int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } + } + } + ["static"]=> + array(1) { + ["outer"]=> + &int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } + } + } + ["static"]=> + array(1) { + ["outer"]=> + &int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } +} +object(Closure)#%d (3) { + ["this"]=> + NULL + ["static"]=> + array(1) { + ["outer"]=> + int(25) + } + ["parameter"]=> + array(2) { + ["$param"]=> + string(10) "" + ["$other"]=> + string(10) "" + } +} +===DONE=== diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index f2e5024f41d..1f65e11668c 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 c326e329c47..006af066714 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 57f7d3d2e34..27f1461a1ee 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) {