On Thu, 05 Aug 2010 14:54:21 +0100, Gustavo Lopes <glo...@nebm.ist.utl.pt>
wrote:
Hi
I've modified Closure::bindTo/Closure::bindTo so that they accept another
argument that defines the new scope. This can either be an object (its
class is used as the scope) or a class name.
[...]
Sending renamed attachments.
--
Gustavo Lopes
---- EXPECTED OUTPUT
int(-4)
Testing with scope given as object
int(21)
int(22)
Testing with scope as string
int(23)
int(24)
Fatal error: Using $this when not in object context in %s on line %d
---- ACTUAL OUTPUT
int(-4)
Testing with scope given as object
int(11)
int(12)
Testing with scope as string
int(21)
Fatal error: Function name must be a string in
D:\Users\Cataphract\Documents\php-trunk\Zend\tests\closure_039.php on line 40
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x029c17c0 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x029c17c0 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x029c17c0 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
---- FAILED
Index: tests/closure_036.phpt
===================================================================
--- tests/closure_036.phpt (revision 301876)
+++ tests/closure_036.phpt (working copy)
@@ -1,5 +1,5 @@
--TEST--
-Closure 036: Rebinding closures
+Closure 036: Rebinding closures, keep calling scope
--FILE--
<?php
@@ -20,7 +20,7 @@
$ca = $a->getIncrementor();
$cb = $ca->bindTo($b);
-$cb2 = Closure::bind($b, $ca);
+$cb2 = Closure::bind($ca, $b);
var_dump($ca());
var_dump($cb());
Index: tests/closure_038.phpt
===================================================================
--- tests/closure_038.phpt (revision 0)
+++ tests/closure_038.phpt (revision 0)
@@ -0,0 +1,58 @@
+--TEST--
+Closure 038: Rebinding closures, change scope, different runtime type
+--FILE--
+<?php
+
+class A {
+ private $x;
+
+ public function __construct($v) {
+ $this->x = $v;
+ }
+
+ public function getIncrementor() {
+ return function() { return ++$this->x; };
+ }
+}
+class B extends A {
+ private $x;
+ public function __construct($v) {
+ parent::__construct($v);
+ $this->x = $v*2;
+ }
+}
+
+$a = new A(0);
+$b = new B(10);
+
+$ca = $a->getIncrementor();
+var_dump($ca());
+
+echo "Testing with scope given as object", "\n";
+
+$cb = $ca->bindTo($b, $b);
+$cb2 = Closure::bind($ca, $b, $b);
+var_dump($cb());
+var_dump($cb2());
+
+echo "Testing with scope as string", "\n";
+
+$cb = $ca->bindTo($b, 'B');
+$cb2 = Closure::bind($ca, $b, 'B');
+var_dump($cb());
+var_dump($cb2());
+
+$cb = $ca->bindTo($b, NULL);
+var_dump($cb());
+
+?>
+--EXPECTF--
+int(1)
+Testing with scope given as object
+int(21)
+int(22)
+Testing with scope as string
+int(23)
+int(24)
+
+Fatal error: Using $this when not in object context in %s on line %d
\ No newline at end of file
Index: tests/closure_039.phpt
===================================================================
--- tests/closure_039.phpt (revision 0)
+++ tests/closure_039.phpt (revision 0)
@@ -0,0 +1,58 @@
+--TEST--
+Closure 039: Rebinding closures, change scope, same runtime type
+--FILE--
+<?php
+
+class A {
+ private $x;
+
+ public function __construct($v) {
+ $this->x = $v;
+ }
+
+ public function getIncrementor() {
+ return function() { return ++$this->x; };
+ }
+}
+class B extends A {
+ private $x;
+ public function __construct($v) {
+ parent::__construct($v);
+ $this->x = $v*2;
+ }
+}
+
+$a = new B(-5);
+$b = new B(10);
+
+$ca = $a->getIncrementor();
+var_dump($ca());
+
+echo "Testing with scope given as object", "\n";
+
+$cb = $ca->bindTo($b, $b);
+$cb2 = Closure::bind($ca, $b, $b);
+var_dump($cb());
+var_dump($cb2());
+
+echo "Testing with scope as string", "\n";
+
+$cb = $ca->bindTo($b, 'B');
+$cb2 = Closure::bind($ca, $b, 'B');
+var_dump($cb());
+var_dump($cb2());
+
+$cb = $ca->bindTo($b, NULL);
+var_dump($cb());
+
+?>
+--EXPECTF--
+int(-4)
+Testing with scope given as object
+int(21)
+int(22)
+Testing with scope as string
+int(23)
+int(24)
+
+Fatal error: Using $this when not in object context in %s on line %d
\ No newline at end of file
Index: tests/closure_040.phpt
===================================================================
--- tests/closure_040.phpt (revision 0)
+++ tests/closure_040.phpt (revision 0)
@@ -0,0 +1,45 @@
+--TEST--
+Closure 040: Rebinding closures, bad arguments
+--FILE--
+<?php
+
+class A {
+ private $x;
+ private static $xs = 10;
+
+ public function __construct($v) {
+ $this->x = $v;
+ }
+
+ public function getIncrementor() {
+ return function() { return ++$this->x; };
+ }
+ public function getStaticIncrementor() {
+ return static function() { return ++static::$xs; };
+ }
+}
+
+$a = new A(20);
+
+$ca = $a->getIncrementor();
+$cas = $a->getStaticIncrementor();
+
+$ca->bindTo($a, array());
+$ca->bindTo(array(), 'A');
+$ca->bindTo($a, array(), "");
+$ca->bindTo();
+$cas->bindTo($a, 'A');
+
+?>
+--EXPECTF--
+Notice: Array to string conversion in %s on line %d
+
+Warning: Class 'Array' not found in %s on line %d
+
+Warning: Closure::bindTo() expects parameter 1 to be object, array given in %s
on line 25
+
+Warning: Closure::bindTo() expects at most 2 parameters, 3 given in %s on line
%d
+
+Warning: Closure::bindTo() expects at least 1 parameter, 0 given in %s on line
%d
+
+Warning: Tried to bind an instance to a static closure in %s on line %d
\ No newline at end of file
Index: tests/closure_041.phpt
===================================================================
--- tests/closure_041.phpt (revision 0)
+++ tests/closure_041.phpt (revision 0)
@@ -0,0 +1,40 @@
+--TEST--
+Closure 041: Closure->getScope()
+--FILE--
+<?php
+
+class A {
+ private $x;
+ private static $xs = 10;
+
+ public function __construct($v) {
+ $this->x = $v;
+ }
+
+ public function getIncrementor() {
+ return function() { return ++$this->x; };
+ }
+ public function getStaticIncrementor() {
+ return static function() { return ++static::$xs; };
+ }
+}
+
+$a = new A(20);
+
+$c = function() {};
+$ca = $a->getIncrementor();
+$cas = $a->getStaticIncrementor();
+
+var_dump($c->getScope());
+var_dump($ca->getScope());
+var_dump($cas->getScope());
+var_dump($cas->getScope(array()));
+
+?>
+--EXPECTF--
+NULL
+string(1) "A"
+string(1) "A"
+
+Warning: Closure::getScope() expects exactly 0 parameters, 1 given in %s on
line %d
+NULL
\ No newline at end of file
Index: zend_closures.c
===================================================================
--- zend_closures.c (revision 301876)
+++ zend_closures.c (working copy)
@@ -76,39 +76,81 @@
}
/* }}} */
-/* {{{ proto Closure Closure::bindTo(object $to)
- Bind a closure to another object */
-ZEND_METHOD(Closure, bindTo) /* {{{ */
+/* {{{ proto Closure Closure::bind(Closure $old, object $to [, mixed $scope =
$this->getScope() ] )
+ Create a closure from another one and bind to another object and scope */
+ZEND_METHOD(Closure, bind) /* {{{ */
{
- zval *newthis;
- zend_closure *closure = (zend_closure
*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval *newthis, *zclosure, *scope_arg = NULL;
+ zend_closure *closure;
+ zend_class_entry *ce, **ce_p;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!", &newthis) ==
FAILURE) {
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
"Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
RETURN_NULL();
}
- zend_create_closure(return_value, &closure->func,
newthis?Z_OBJCE_P(newthis):NULL, newthis TSRMLS_CC);
+ closure = (zend_closure *)zend_object_store_get_object(zclosure
TSRMLS_CC);
+
+ if ((newthis != NULL) && (closure->func.common.fn_flags &
ZEND_ACC_STATIC)) {
+ zend_error(E_WARNING, "Tried to bind an instance to a static
closure");
+ }
+
+ if (scope_arg != NULL) { /* scope argument was given */
+ if (IS_ZEND_STD_OBJECT(*scope_arg)) {
+ ce = Z_OBJCE_P(scope_arg);
+ } else if (Z_TYPE_P(scope_arg) == IS_NULL) {
+ ce = NULL;
+ } else {
+ char *class_name;
+ int class_name_len;
+ zval tmp_zval;
+ INIT_ZVAL(tmp_zval);
+
+ if (Z_TYPE_P(scope_arg) == IS_STRING) {
+ class_name = Z_STRVAL_P(scope_arg);
+ class_name_len = Z_STRLEN_P(scope_arg);
+ } else {
+ tmp_zval = *scope_arg;
+ zval_copy_ctor(&tmp_zval);
+ convert_to_string(&tmp_zval);
+ class_name = Z_STRVAL(tmp_zval);
+ class_name_len = Z_STRLEN(tmp_zval);
+ }
+
+ if (zend_lookup_class_ex(class_name, class_name_len,
NULL, 1, &ce_p TSRMLS_CC) == FAILURE) {
+ zend_error(E_WARNING, "Class '%s' not found",
class_name);
+ RETURN_NULL();
+ } else {
+ ce = *ce_p;
+ }
+ zval_dtor(&tmp_zval);
+ }
+ } else { /* scope argument not given; do not change the scope by
default */
+ ce = closure->func.common.scope;
+ }
+
+ zend_create_closure(return_value, &closure->func, ce, newthis
TSRMLS_CC);
}
/* }}} */
-/* {{{ proto Closure Closure::bind(object $to, Closure $old)
- Create a closure to with binding to another object */
-ZEND_METHOD(Closure, bind) /* {{{ */
+ZEND_METHOD(Closure, getScope)
{
- zval *newthis, *zclosure;
- zend_closure *closure;
+ zend_closure *closure;
+ zend_class_entry *ce;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!O", &newthis,
&zclosure, zend_ce_closure) == FAILURE) {
+ if (zend_parse_parameters_none() == FAILURE) {
RETURN_NULL();
}
- closure = (zend_closure *)zend_object_store_get_object(zclosure
TSRMLS_CC);
+ closure = (zend_closure *)zend_object_store_get_object(getThis()
TSRMLS_CC);
+ ce = closure->func.common.scope;
- zend_create_closure(return_value, &closure->func,
newthis?Z_OBJCE_P(newthis):NULL, newthis TSRMLS_CC);
+ if (ce != NULL) {
+ RETURN_STRINGL(ce->name, ce->name_length, 1);
+ } else {
+ RETURN_NULL();
+ }
}
-/* }}} */
-
static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /*
{{{ */
{
zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not
allowed");
@@ -356,19 +398,25 @@
}
/* }}} */
-ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 0)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 1)
ZEND_ARG_INFO(0, newthis)
+ ZEND_ARG_INFO(0, newscope)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 0)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 2)
+ ZEND_ARG_INFO(0, closure)
ZEND_ARG_INFO(0, newthis)
- ZEND_ARG_INFO(0, closure)
+ ZEND_ARG_INFO(0, newscope)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_getscope, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
static const zend_function_entry closure_functions[] = {
ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
- ZEND_ME(Closure, bindTo, arginfo_closure_bindto, ZEND_ACC_PUBLIC)
ZEND_ME(Closure, bind, arginfo_closure_bind,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ ZEND_MALIAS(Closure, bindTo, bind, arginfo_closure_bindto,
ZEND_ACC_PUBLIC)
+ ZEND_ME(Closure, getScope, arginfo_closure_getscope, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
---- EXPECTED OUTPUT
int(1)
Testing with scope given as object
int(21)
int(22)
Testing with scope as string
int(23)
int(24)
Fatal error: Using $this when not in object context in %s on line %d
---- ACTUAL OUTPUT
int(1)
Testing with scope given as object
int(21)
int(22)
Testing with scope as string
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x02741730 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
int(23)
int(24)
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x02741730 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
Fatal error: Using $this when not in object context in
D:\Users\Cataphract\Documents\php-trunk\Zend\tests\closure_038.php on line 11
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x02741730 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x02741730 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
---------------------------------------
d:\users\cataphract\documents\php-trunk\zend\zend_opcode.c(373) : Block
0x02741730 status:
Beginning: Cached
Freed (invalid)
Start: OK
End: OK
---------------------------------------
---- FAILED
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php