diff --git a/Zend/tests/closures/closure_get_current.phpt b/Zend/tests/closures/closure_get_current.phpt new file mode 100644 index 0000000000000..3024ff355b558 --- /dev/null +++ b/Zend/tests/closures/closure_get_current.phpt @@ -0,0 +1,64 @@ +--TEST-- +Closure::getCurrent() +--FILE-- +getMessage(), "\n"; +} + +function foo() { + var_dump(Closure::getCurrent()); +} + +try { + foo(...)(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +int(1) +int(1) +int(2) +int(2) +int(3) +int(3) +int(4) +int(4) +int(5) +int(5) +int(6) +int(6) +int(7) +int(7) +int(8) +int(8) +int(9) +int(9) +int(10) +int(10) +int(11) +Current function is not a closure +Current function is not a closure diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 5777e1a34a2b8..bdcdc329647ca 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -418,6 +418,23 @@ ZEND_METHOD(Closure, fromCallable) } /* }}} */ +ZEND_METHOD(Closure, getCurrent) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_execute_data *prev_ex = EX(prev_execute_data); + + if (!prev_ex + || !prev_ex->func + || (prev_ex->func->common.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) { + zend_throw_error(NULL, "Current function is not a closure"); + RETURN_THROWS(); + } + + zend_object *obj = ZEND_CLOSURE_OBJECT(prev_ex->func); + RETURN_OBJ_COPY(obj); +} + static ZEND_COLD zend_function *zend_closure_get_constructor(zend_object *object) /* {{{ */ { zend_throw_error(NULL, "Instantiation of class Closure is not allowed"); diff --git a/Zend/zend_closures.stub.php b/Zend/zend_closures.stub.php index daa92492b1884..46b51617eef98 100644 --- a/Zend/zend_closures.stub.php +++ b/Zend/zend_closures.stub.php @@ -21,4 +21,6 @@ public function bindTo(?object $newThis, object|string|null $newScope = "static" public function call(object $newThis, mixed ...$args): mixed {} public static function fromCallable(callable $callback): Closure {} + + public static function getCurrent(): Closure {} } diff --git a/Zend/zend_closures_arginfo.h b/Zend/zend_closures_arginfo.h index 57066078a8821..4ce02c40e55a7 100644 --- a/Zend/zend_closures_arginfo.h +++ b/Zend/zend_closures_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e3b480674671a698814db282c5ea34d438fe519d */ + * Stub hash: e0626e52adb2d38dad1140c1a28cc7774cc84500 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Closure___construct, 0, 0, 0) ZEND_END_ARG_INFO() @@ -24,11 +24,15 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Closure_fromCallable, 0, 1, ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Closure_getCurrent, 0, 0, Closure, 0) +ZEND_END_ARG_INFO() + ZEND_METHOD(Closure, __construct); ZEND_METHOD(Closure, bind); ZEND_METHOD(Closure, bindTo); ZEND_METHOD(Closure, call); ZEND_METHOD(Closure, fromCallable); +ZEND_METHOD(Closure, getCurrent); static const zend_function_entry class_Closure_methods[] = { ZEND_ME(Closure, __construct, arginfo_class_Closure___construct, ZEND_ACC_PRIVATE) @@ -36,6 +40,7 @@ static const zend_function_entry class_Closure_methods[] = { ZEND_ME(Closure, bindTo, arginfo_class_Closure_bindTo, ZEND_ACC_PUBLIC) ZEND_ME(Closure, call, arginfo_class_Closure_call, ZEND_ACC_PUBLIC) ZEND_ME(Closure, fromCallable, arginfo_class_Closure_fromCallable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Closure, getCurrent, arginfo_class_Closure_getCurrent, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_FE_END };