]> granicus.if.org Git - php/commitdiff
Fixed bug #75186
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 9 May 2019 10:29:33 +0000 (12:29 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 9 May 2019 10:33:53 +0000 (12:33 +0200)
NEWS
ext/reflection/php_reflection.c
ext/reflection/tests/bug75186.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index cc605a6c8ee862da381cfe720360bef163fd799a..f774605940b4cf308d451dc23ed439067476f0f8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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)
 
index 0a59d9a74c678a369ace90ad834518208eca827e..012f23982d9d94728b4da252b9f21f9de8afd4df 100644 (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);
                }
        }
 }
diff --git a/ext/reflection/tests/bug75186.phpt b/ext/reflection/tests/bug75186.phpt
new file mode 100644 (file)
index 0000000..04563af
--- /dev/null
@@ -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!