]> granicus.if.org Git - php/commitdiff
- MFH Rebind closure when binding to property
authorMarcus Boerger <helly@php.net>
Sat, 3 Jan 2009 17:48:40 +0000 (17:48 +0000)
committerMarcus Boerger <helly@php.net>
Sat, 3 Jan 2009 17:48:40 +0000 (17:48 +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..c919671
--- /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) {
+    ["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===
index f2e5024f41df8a55d9d65289a0760a9bd2d9b6bd..1f65e11668c7b2d8241f79c48e76a02108c01fff 100644 (file)
@@ -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;
index c326e329c4739e2acb10f2d48d0f6008360a6efe..006af0667146a17d7b12912fd11e90489eb87e0d 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 57f7d3d2e34e2cd49183896fe4c079be09b62b6a..27f1461a1ee341ff453197fb0e5150104544ecc2 100644 (file)
@@ -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) {