- MFH Rebind closure when binding to property

This commit is contained in:
Marcus Boerger 2009-01-03 17:48:40 +00:00
parent 7ca830742e
commit 0e131653c1
5 changed files with 278 additions and 1 deletions

28
Zend/tests/closure_033.phpt Executable file
View File

@ -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

233
Zend/tests/closure_034.phpt Executable file
View File

@ -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 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;

View 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()

View 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) {