]> granicus.if.org Git - php/commitdiff
Forbid binding methods to incompatible $this
authorNikita Popov <nikic@php.net>
Tue, 29 Mar 2016 21:48:07 +0000 (23:48 +0200)
committerNikita Popov <nikic@php.net>
Thu, 7 Apr 2016 22:38:44 +0000 (00:38 +0200)
This prohibits binding closures returned by
ReflectionMethod::getClosure() to a $this, which is not an
instance of the method scope. This restriction was already in
place for internal methods, now it is extended to user methods.

ML discussion: http://markmail.org/message/zepnhdyr3kij6di6

Zend/tests/bug70685.phpt
Zend/tests/closure_061.phpt
Zend/zend_closures.c

index 7a49ff1825928df67b6f6ab1d417a04e2c05e5fe..8ae97f1bf0caecf1dac7633fa0baf5094860afe0 100644 (file)
@@ -15,7 +15,7 @@ var_dump($c);
 
 ?>
 --EXPECTF--
-Warning: Cannot bind internal method SplDoublyLinkedList::count() to object of class cls in %s on line %d
+Warning: Cannot bind method SplDoublyLinkedList::count() to object of class cls in %s on line %d
 NULL
 
 Warning: Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure() in %s on line %d
index 83ad16d2e15ade14939f3ef1b18657610f544a6e..1aa579a40959a9c7c32794eaebeec08c87d94285 100644 (file)
@@ -184,7 +184,7 @@ bindTo(new ClsChild, Cls::class):
 Success!
 
 bindTo(new ClsUnrelated, Cls::class):
-Success!
+Cannot bind method Cls::method() to object of class ClsUnrelated
 
 bindTo(new Cls, null):
 Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
@@ -205,7 +205,7 @@ bindTo(new SplStack, SplDoublyLinkedList::class):
 Success!
 
 bindTo(new ClsUnrelated, SplDoublyLinkedList::class):
-Cannot bind internal method SplDoublyLinkedList::count() to object of class ClsUnrelated
+Cannot bind method SplDoublyLinkedList::count() to object of class ClsUnrelated
 
 bindTo(null, null):
 Cannot unbind $this of internal method
index d52d0b5c257a634d8c06108f652010d64a8634ce..fd0738f32f95df7865dc33de01b14298fe2f393d 100644 (file)
@@ -77,16 +77,17 @@ static zend_bool zend_valid_closure_binding(
                zend_closure *closure, zval *newthis, zend_class_entry *scope) /* {{{ */
 {
        zend_function *func = &closure->func;
+       zend_bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0;
        if (newthis) {
                if (func->common.fn_flags & ZEND_ACC_STATIC) {
                        zend_error(E_WARNING, "Cannot bind an instance to a static closure");
                        return 0;
                }
 
-               if (func->type == ZEND_INTERNAL_FUNCTION && func->common.scope &&
+               if (is_fake_closure && func->common.scope &&
                                !instanceof_function(Z_OBJCE_P(newthis), func->common.scope)) {
                        /* Binding incompatible $this to an internal method is not supported. */
-                       zend_error(E_WARNING, "Cannot bind internal method %s::%s() to object of class %s",
+                       zend_error(E_WARNING, "Cannot bind method %s::%s() to object of class %s",
                                        ZSTR_VAL(func->common.scope->name),
                                        ZSTR_VAL(func->common.function_name),
                                        ZSTR_VAL(Z_OBJCE_P(newthis)->name));
@@ -105,7 +106,7 @@ static zend_bool zend_valid_closure_binding(
                return 0;
        }
 
-       if ((func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) && scope != func->common.scope) {
+       if (is_fake_closure && scope != func->common.scope) {
                zend_error(E_WARNING, "Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()");
                return 0;
        }