]> granicus.if.org Git - php/commitdiff
- Rebind closure when binding to property
authorMarcus Boerger <helly@php.net>
Sat, 3 Jan 2009 17:46:25 +0000 (17:46 +0000)
committerMarcus Boerger <helly@php.net>
Sat, 3 Jan 2009 17:46:25 +0000 (17:46 +0000)
Zend/tests/closure_033.phpt [new file with mode: 0755]
Zend/tests/closure_034.phpt [new file with mode: 0755]
Zend/zend_closures.c
Zend/zend_closures.h
Zend/zend_object_handlers.c

diff --git a/Zend/tests/closure_033.phpt b/Zend/tests/closure_033.phpt
new file mode 100755 (executable)
index 0000000..f651006
--- /dev/null
@@ -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 (executable)
index 0000000..8a94c75
--- /dev/null
@@ -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) {
+    [u"func1"]=>
+    object(Closure)#%d (3) {
+      ["this"]=>
+      object(Test)#%d (2) {
+        [u"func1"]=>
+        object(Closure)#%d (3) {
+          ["this"]=>
+          *RECURSION*
+          ["static"]=>
+          array(1) {
+            [u"outer"]=>
+            int(25)
+          }
+          ["parameter"]=>
+          array(2) {
+            ["$param"]=>
+            string(10) "<required>"
+            ["$other"]=>
+            string(10) "<optional>"
+          }
+        }
+        [u"var"]=>
+        int(42)
+      }
+      ["static"]=>
+      array(1) {
+        [u"outer"]=>
+        int(25)
+      }
+      ["parameter"]=>
+      array(2) {
+        ["$param"]=>
+        string(10) "<required>"
+        ["$other"]=>
+        string(10) "<optional>"
+      }
+    }
+    [u"var"]=>
+    int(42)
+  }
+  ["static"]=>
+  array(1) {
+    [u"outer"]=>
+    int(25)
+  }
+  ["parameter"]=>
+  array(2) {
+    ["$param"]=>
+    string(10) "<required>"
+    ["$other"]=>
+    string(10) "<optional>"
+  }
+}
+object(Closure)#%d (3) {
+  ["this"]=>
+  object(Test)#%d (3) {
+    [u"func1"]=>
+    object(Closure)#%d (3) {
+      ["this"]=>
+      object(Test)#%d (3) {
+        [u"func1"]=>
+        object(Closure)#%d (3) {
+          ["this"]=>
+          *RECURSION*
+          ["static"]=>
+          array(1) {
+            [u"outer"]=>
+            int(25)
+          }
+          ["parameter"]=>
+          array(2) {
+            ["$param"]=>
+            string(10) "<required>"
+            ["$other"]=>
+            string(10) "<optional>"
+          }
+        }
+        [u"var"]=>
+        int(42)
+        [u"func2"]=>
+        object(Closure)#%d (3) {
+          ["this"]=>
+          *RECURSION*
+          ["static"]=>
+          array(1) {
+            [u"outer"]=>
+            &int(25)
+          }
+          ["parameter"]=>
+          array(2) {
+            ["$param"]=>
+            string(10) "<required>"
+            ["$other"]=>
+            string(10) "<optional>"
+          }
+        }
+      }
+      ["static"]=>
+      array(1) {
+        [u"outer"]=>
+        int(25)
+      }
+      ["parameter"]=>
+      array(2) {
+        ["$param"]=>
+        string(10) "<required>"
+        ["$other"]=>
+        string(10) "<optional>"
+      }
+    }
+    [u"var"]=>
+    int(42)
+    [u"func2"]=>
+    object(Closure)#%d (3) {
+      ["this"]=>
+      object(Test)#%d (3) {
+        [u"func1"]=>
+        object(Closure)#%d (3) {
+          ["this"]=>
+          *RECURSION*
+          ["static"]=>
+          array(1) {
+            [u"outer"]=>
+            int(25)
+          }
+          ["parameter"]=>
+          array(2) {
+            ["$param"]=>
+            string(10) "<required>"
+            ["$other"]=>
+            string(10) "<optional>"
+          }
+        }
+        [u"var"]=>
+        int(42)
+        [u"func2"]=>
+        object(Closure)#%d (3) {
+          ["this"]=>
+          *RECURSION*
+          ["static"]=>
+          array(1) {
+            [u"outer"]=>
+            &int(25)
+          }
+          ["parameter"]=>
+          array(2) {
+            ["$param"]=>
+            string(10) "<required>"
+            ["$other"]=>
+            string(10) "<optional>"
+          }
+        }
+      }
+      ["static"]=>
+      array(1) {
+        [u"outer"]=>
+        &int(25)
+      }
+      ["parameter"]=>
+      array(2) {
+        ["$param"]=>
+        string(10) "<required>"
+        ["$other"]=>
+        string(10) "<optional>"
+      }
+    }
+  }
+  ["static"]=>
+  array(1) {
+    [u"outer"]=>
+    &int(25)
+  }
+  ["parameter"]=>
+  array(2) {
+    ["$param"]=>
+    string(10) "<required>"
+    ["$other"]=>
+    string(10) "<optional>"
+  }
+}
+object(Closure)#%d (3) {
+  ["this"]=>
+  NULL
+  ["static"]=>
+  array(1) {
+    [u"outer"]=>
+    int(25)
+  }
+  ["parameter"]=>
+  array(2) {
+    ["$param"]=>
+    string(10) "<required>"
+    ["$other"]=>
+    string(10) "<optional>"
+  }
+}
+===DONE===
index b77ae9657acafd3e6b0586bfcf050df6506dac96..5aeb09667b148faae638139e676ce2d48e41f0ec 100644 (file)
@@ -122,6 +122,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, zstr method_name, int method_len TSRMLS_DC) /* {{{ */
 {
        unsigned int lc_name_len;
@@ -243,7 +254,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;
index bd0e2c4b4a102522bcaf5ef93f0a535d2973e278..0358a36bd5a3e803b63b9caf4a80527844f7c443 100644 (file)
@@ -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()
 
index 4a24551d798f5e81ac84c3821970666e2fed522b..a38887bb60d8543ca44df260bf767955f456a1fa 100644 (file)
@@ -413,6 +413,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_u_hash_quick_find(zobj->properties, Z_TYPE_P(member), property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) {