This commit is contained in:
Nikita Popov 2019-05-09 12:29:33 +02:00
parent e359812ce3
commit 35c80583f0
3 changed files with 48 additions and 21 deletions

3
NEWS
View File

@ -14,6 +14,9 @@ PHP NEWS
- PDO_MySQL:
. Fixed bug #77944 (Wrong meta pdo_type for bigint on LLP64). (cmb)
- Reflection:
. Fixed bug #75186 (Inconsistent reflection of Closure:::__invoke()). (Nikita)
- Session:
. Fixed bug #77911 (Wrong warning for session.sid_bits_per_character). (cmb)

View File

@ -4203,22 +4203,10 @@ ZEND_METHOD(reflection_class, getMethod)
/* }}} */
/* {{{ _addmethod */
static void _addmethod(zend_function *mptr, zend_class_entry *ce, zval *retval, zend_long filter, zval *obj)
static void _addmethod(zend_function *mptr, zend_class_entry *ce, zval *retval, zend_long filter)
{
zval method;
size_t len = ZSTR_LEN(mptr->common.function_name);
zend_function *closure;
if (mptr->common.fn_flags & filter) {
if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
&& memcmp(ZSTR_VAL(mptr->common.function_name), ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
&& (closure = zend_get_closure_invoke_method(Z_OBJ_P(obj))) != NULL)
{
_fix_closure_prototype(closure);
mptr = closure;
}
/* don't assign closure_object since we only reflect the invoke handler
method and not the closure definition itself, even if we have a
closure */
zval method;
reflection_method_factory(ce, mptr, NULL, &method);
add_next_index_zval(retval, &method);
}
@ -4232,9 +4220,8 @@ static int _addmethod_va(zval *el, int num_args, va_list args, zend_hash_key *ha
zend_class_entry *ce = *va_arg(args, zend_class_entry**);
zval *retval = va_arg(args, zval*);
long filter = va_arg(args, long);
zval *obj = va_arg(args, zval *);
_addmethod(mptr, ce, retval, filter, obj);
_addmethod(mptr, ce, retval, filter);
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
@ -4260,13 +4247,25 @@ ZEND_METHOD(reflection_class, getMethods)
GET_REFLECTION_OBJECT_PTR(ce);
array_init(return_value);
zend_hash_apply_with_arguments(&ce->function_table, (apply_func_args_t) _addmethod_va, 4, &ce, return_value, filter, intern->obj);
if (Z_TYPE(intern->obj) != IS_UNDEF && instanceof_function(ce, zend_ce_closure)) {
zend_function *closure = zend_get_closure_invoke_method(Z_OBJ(intern->obj));
zend_hash_apply_with_arguments(&ce->function_table, (apply_func_args_t) _addmethod_va, 4, &ce, return_value, filter);
if (instanceof_function(ce, zend_ce_closure)) {
zend_bool has_obj = Z_TYPE(intern->obj) != IS_UNDEF;
zval obj_tmp;
zend_object *obj;
if (!has_obj) {
object_init_ex(&obj_tmp, ce);
obj = Z_OBJ(obj_tmp);
} else {
obj = Z_OBJ(intern->obj);
}
zend_function *closure = zend_get_closure_invoke_method(obj);
if (closure) {
_fix_closure_prototype(closure);
_addmethod(closure, ce, return_value, filter, &intern->obj);
_free_function(closure);
_addmethod(closure, ce, return_value, filter);
}
if (!has_obj) {
zval_ptr_dtor(&obj_tmp);
}
}
}

View File

@ -0,0 +1,25 @@
--TEST--
Bug #75186: Inconsistent reflection of Closure:::__invoke()
--FILE--
<?php
$rc = new ReflectionClass(Closure::class);
foreach ($rc->getMethods() as $method) {
if ($method->name == '__invoke') {
var_dump($method);
$method->invoke(
function($what) { echo "Hello $what!\n"; },
"World"
);
}
}
?>
--EXPECTF--
object(ReflectionMethod)#%d (2) {
["name"]=>
string(8) "__invoke"
["class"]=>
string(7) "Closure"
}
Hello World!