]> granicus.if.org Git - php/commitdiff
Fixed bug #78689
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 29 Oct 2019 14:05:59 +0000 (15:05 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 29 Oct 2019 14:06:16 +0000 (15:06 +0100)
NEWS
Zend/tests/bug78689.phpt [new file with mode: 0644]
Zend/zend_closures.c

diff --git a/NEWS b/NEWS
index 6fba02d9c88639925045b9903cfef9135256ac0a..b56409b4afa2ccbcc9f1e10657c9568a4a2c98d2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ PHP                                                                        NEWS
     Lundin)
   . Fixed bug #78752 (Segfault if GC triggered while generator stack frame is
     being destroyed). (Nikita)
+  . Fixed bug #78689 (Closure::fromCallable() doesn't handle
+    [Closure, '__invoke']). (Nikita)
 
 - COM:
   . Fixed bug #78694 (Appending to a variant array causes segfault). (cmb)
diff --git a/Zend/tests/bug78689.phpt b/Zend/tests/bug78689.phpt
new file mode 100644 (file)
index 0000000..2273fd3
--- /dev/null
@@ -0,0 +1,13 @@
+--TEST--
+Bug #78689: Closure::fromCallable() doesn't handle [Closure, '__invoke']
+--FILE--
+<?php
+$a = [function () { echo "123\n"; }, '__invoke'];
+$a();
+
+$b = Closure::fromCallable($a);
+$b();
+?>
+--EXPECT--
+123
+123
index 23ea9bc2e2592dca3a1fe688c7b073572a6592f4..3efb7ea11665bd58f17f6968bd93a4df60f3e831 100644 (file)
@@ -268,8 +268,15 @@ static int zend_create_closure_from_callable(zval *return_value, zval *callable,
 
        mptr = fcc.function_handler;
        if (mptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
-               memset(&call, 0, sizeof(zend_internal_function));
+               /* For Closure::fromCallable([$closure, "__invoke"]) return $closure. */
+               if (fcc.object && fcc.object->ce == zend_ce_closure
+                               && zend_string_equals_literal(mptr->common.function_name, "__invoke")) {
+                       ZVAL_OBJ(return_value, fcc.object);
+                       zend_free_trampoline(mptr);
+                       return SUCCESS;
+               }
 
+               memset(&call, 0, sizeof(zend_internal_function));
                call.type = ZEND_INTERNAL_FUNCTION;
                call.handler = zend_closure_call_magic;
                call.function_name = mptr->common.function_name;