mirror of
https://github.com/php/php-src.git
synced 2024-09-25 11:57:26 +00:00
Merge branch 'PHP-7.0'
This commit is contained in:
commit
2f06c0b2ea
@ -7,4 +7,4 @@ $x = (new ReflectionFunction("substr"))->getClosure();
|
||||
$x->call(new a);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: a::substr() expects at least 2 parameters, 0 given in %s on line %d
|
||||
Warning: Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure() in %s on line %d
|
||||
|
@ -18,5 +18,5 @@ var_dump($c);
|
||||
Warning: Cannot bind internal method SplDoublyLinkedList::count() to object of class cls in %s on line %d
|
||||
NULL
|
||||
|
||||
Warning: Cannot bind function SplDoublyLinkedList::count to scope class cls in %s on line %d
|
||||
Warning: Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure() in %s on line %d
|
||||
NULL
|
||||
|
208
Zend/tests/closure_061.phpt
Normal file
208
Zend/tests/closure_061.phpt
Normal file
@ -0,0 +1,208 @@
|
||||
--TEST--
|
||||
Rebinding of ::getClosure()s
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
use SplDoublyLinkedList as DLL;
|
||||
|
||||
function func($arg) { }
|
||||
|
||||
class Cls {
|
||||
public function method() {}
|
||||
public static function staticMethod($arg) {}
|
||||
}
|
||||
|
||||
class ClsChild extends Cls {}
|
||||
|
||||
class ClsUnrelated {}
|
||||
|
||||
/* Format: [Function, [Obj, Scope]] */
|
||||
$tests = [
|
||||
['func', [
|
||||
[null, null],
|
||||
[new Cls, null],
|
||||
[new Cls, 'Cls'],
|
||||
[null, 'Cls'],
|
||||
[null, 'stdClass'],
|
||||
[new stdClass, null],
|
||||
]],
|
||||
|
||||
['strlen', [
|
||||
[null, null],
|
||||
[new Cls, null],
|
||||
[new Cls, 'Cls'],
|
||||
[null, 'Cls'],
|
||||
[null, 'stdClass'],
|
||||
[new stdClass, null],
|
||||
]],
|
||||
|
||||
[['Cls', 'staticMethod'], [
|
||||
[null, 'Cls'],
|
||||
[new Cls, null],
|
||||
[new Cls, 'Cls'],
|
||||
[null, null],
|
||||
[null, 'ClsChild'],
|
||||
[null, 'ClsUnrelated'],
|
||||
]],
|
||||
|
||||
[[new Cls, 'method'], [
|
||||
[null, 'Cls'],
|
||||
[new Cls, 'Cls'],
|
||||
[new ClsChild, 'Cls'],
|
||||
[new ClsUnrelated, 'Cls'],
|
||||
[new Cls, null],
|
||||
[new Cls, 'ClsUnrelated'],
|
||||
[new Cls, 'ClsChild'],
|
||||
]],
|
||||
|
||||
[[new DLL, 'count'], [
|
||||
[new DLL, DLL::class],
|
||||
[new SplStack, DLL::class],
|
||||
[new ClsUnrelated, DLL::class],
|
||||
[null, null],
|
||||
[null, DLL::class],
|
||||
[new DLL, null],
|
||||
[new DLL, ClsUnrelated::class],
|
||||
]],
|
||||
];
|
||||
|
||||
set_error_handler(function($errno, $errstr) {
|
||||
echo "$errstr\n\n";
|
||||
});
|
||||
|
||||
foreach ($tests as list($fn, $bindings)) {
|
||||
if (is_array($fn)) {
|
||||
$r = new ReflectionMethod($fn[0], $fn[1]);
|
||||
$c = $r->getClosure(is_object($fn[0]) ? $fn[0] : null);
|
||||
$fnStr = is_object($fn[0]) ? "(new " . get_class($fn[0]) . ")->$fn[1]" : "$fn[0]::$fn[1]";
|
||||
} else {
|
||||
$c = (new ReflectionFunction($fn))->getClosure();
|
||||
$fnStr = $fn;
|
||||
}
|
||||
|
||||
echo "$fnStr()\n" . str_repeat('-', strlen($fnStr) + 2), "\n\n";
|
||||
|
||||
foreach ($bindings as list($obj, $scope)) {
|
||||
$objStr = $obj ? "new " . get_class($obj) : "null";
|
||||
$scopeStr = $scope ? "$scope::class" : "null";
|
||||
echo "bindTo($objStr, $scopeStr):\n";
|
||||
|
||||
$ret = $c->bindTo($obj, $scope);
|
||||
if ($ret !== null) {
|
||||
echo "Success!\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
func()
|
||||
------
|
||||
|
||||
bindTo(null, null):
|
||||
Success!
|
||||
|
||||
bindTo(new Cls, null):
|
||||
Success!
|
||||
|
||||
bindTo(new Cls, Cls::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(null, Cls::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(null, stdClass::class):
|
||||
Cannot bind closure to scope of internal class stdClass
|
||||
|
||||
bindTo(new stdClass, null):
|
||||
Success!
|
||||
|
||||
strlen()
|
||||
--------
|
||||
|
||||
bindTo(null, null):
|
||||
Success!
|
||||
|
||||
bindTo(new Cls, null):
|
||||
Success!
|
||||
|
||||
bindTo(new Cls, Cls::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(null, Cls::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(null, stdClass::class):
|
||||
Cannot bind closure to scope of internal class stdClass
|
||||
|
||||
bindTo(new stdClass, null):
|
||||
Success!
|
||||
|
||||
Cls::staticMethod()
|
||||
-------------------
|
||||
|
||||
bindTo(null, Cls::class):
|
||||
Success!
|
||||
|
||||
bindTo(new Cls, null):
|
||||
Cannot bind an instance to a static closure
|
||||
|
||||
bindTo(new Cls, Cls::class):
|
||||
Cannot bind an instance to a static closure
|
||||
|
||||
bindTo(null, null):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(null, ClsChild::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(null, ClsUnrelated::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
(new Cls)->method()
|
||||
-------------------
|
||||
|
||||
bindTo(null, Cls::class):
|
||||
Success!
|
||||
|
||||
bindTo(new Cls, Cls::class):
|
||||
Success!
|
||||
|
||||
bindTo(new ClsChild, Cls::class):
|
||||
Success!
|
||||
|
||||
bindTo(new ClsUnrelated, Cls::class):
|
||||
Success!
|
||||
|
||||
bindTo(new Cls, null):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(new Cls, ClsUnrelated::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(new Cls, ClsChild::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
(new SplDoublyLinkedList)->count()
|
||||
----------------------------------
|
||||
|
||||
bindTo(new SplDoublyLinkedList, SplDoublyLinkedList::class):
|
||||
Success!
|
||||
|
||||
bindTo(new SplStack, SplDoublyLinkedList::class):
|
||||
Success!
|
||||
|
||||
bindTo(new ClsUnrelated, SplDoublyLinkedList::class):
|
||||
Cannot bind internal method SplDoublyLinkedList::count() to object of class ClsUnrelated
|
||||
|
||||
bindTo(null, null):
|
||||
Cannot unbind $this of internal method
|
||||
|
||||
bindTo(null, SplDoublyLinkedList::class):
|
||||
Cannot unbind $this of internal method
|
||||
|
||||
bindTo(new SplDoublyLinkedList, null):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
||||
|
||||
bindTo(new SplDoublyLinkedList, ClsUnrelated::class):
|
||||
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
|
@ -34,6 +34,9 @@
|
||||
#define ZEND_CLOSURE_PROPERTY_ERROR() \
|
||||
zend_throw_error(NULL, "Closure object cannot have properties")
|
||||
|
||||
/* reuse bit to mark "fake" closures (it wasn't used for functions before) */
|
||||
#define ZEND_ACC_FAKE_CLOSURE ZEND_ACC_INTERFACE
|
||||
|
||||
typedef struct _zend_closure {
|
||||
zend_object std;
|
||||
zend_function func;
|
||||
@ -102,11 +105,8 @@ static zend_bool zend_valid_closure_binding(
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (func->type == ZEND_INTERNAL_FUNCTION && scope && func->common.scope &&
|
||||
!instanceof_function(scope, func->common.scope)) {
|
||||
zend_error(E_WARNING, "Cannot bind function %s::%s to scope class %s",
|
||||
ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name),
|
||||
ZSTR_VAL(scope->name));
|
||||
if ((func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) && scope != func->common.scope) {
|
||||
zend_error(E_WARNING, "Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -617,6 +617,17 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */
|
||||
{
|
||||
zend_closure *closure;
|
||||
|
||||
zend_create_closure(res, func, scope, called_scope, this_ptr);
|
||||
|
||||
closure = (zend_closure *)Z_OBJ_P(res);
|
||||
closure->func.common.fn_flags |= ZEND_ACC_FAKE_CLOSURE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
|
@ -29,6 +29,7 @@ void zend_register_closure_ce(void);
|
||||
extern ZEND_API zend_class_entry *zend_ce_closure;
|
||||
|
||||
ZEND_API void zend_create_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr);
|
||||
ZEND_API void zend_create_fake_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr);
|
||||
ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *obj);
|
||||
ZEND_API const zend_function *zend_get_closure_method_def(zval *obj);
|
||||
ZEND_API zval* zend_get_closure_this_ptr(zval *obj);
|
||||
|
@ -1762,7 +1762,7 @@ ZEND_METHOD(reflection_function, getClosure)
|
||||
}
|
||||
GET_REFLECTION_OBJECT_PTR(fptr);
|
||||
|
||||
zend_create_closure(return_value, fptr, NULL, NULL, NULL);
|
||||
zend_create_fake_closure(return_value, fptr, NULL, NULL, NULL);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -3144,7 +3144,7 @@ ZEND_METHOD(reflection_method, getClosure)
|
||||
GET_REFLECTION_OBJECT_PTR(mptr);
|
||||
|
||||
if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
|
||||
zend_create_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL);
|
||||
zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL);
|
||||
} else {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) {
|
||||
return;
|
||||
@ -3161,7 +3161,7 @@ ZEND_METHOD(reflection_method, getClosure)
|
||||
{
|
||||
ZVAL_COPY(return_value, obj);
|
||||
} else {
|
||||
zend_create_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj);
|
||||
zend_create_fake_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user