Permalink
Browse files

- MFH Rebind closure when binding to property

  • Loading branch information...
1 parent 7ca8307 commit 0e131653c17b22a1609387d758ffecaf8e8f64bc Marcus Boerger committed Jan 3, 2009
Showing with 278 additions and 1 deletion.
  1. +28 −0 Zend/tests/closure_033.phpt
  2. +233 −0 Zend/tests/closure_034.phpt
  3. +12 −1 Zend/zend_closures.c
  4. +1 −0 Zend/zend_closures.h
  5. +4 −0 Zend/zend_object_handlers.c
@@ -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
@@ -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===
View
@@ -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;
@@ -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()
@@ -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) {

0 comments on commit 0e13165

Please sign in to comment.