diff --git a/Zend/zend_API.h b/Zend/zend_API.h index a2d4e60d7be0d..b21228840c0ce 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -714,7 +714,10 @@ static zend_always_inline zend_result zend_forbid_dynamic_call(void) ZEND_ASSERT(ex != NULL && ex->func != NULL); if (ZEND_CALL_INFO(ex) & ZEND_CALL_DYNAMIC) { - zend_throw_error(NULL, "Cannot call %s() dynamically", get_active_function_name()); + zend_string *function_or_method_name = get_active_function_or_method_name(); + zend_throw_error(NULL, "Cannot call %.*s() dynamically", + (int) ZSTR_LEN(function_or_method_name), ZSTR_VAL(function_or_method_name)); + zend_string_release(function_or_method_name); return FAILURE; } diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 2fbabe7ef647b..6adab9f255cbf 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -41,6 +41,7 @@ static zend_class_entry *zend_test_attribute; static zend_class_entry *zend_test_parameter_attribute; static zend_class_entry *zend_test_class_with_method_with_parameter_attribute; static zend_class_entry *zend_test_child_class_with_method_with_parameter_attribute; +static zend_class_entry *zend_test_forbid_dynamic_call; static zend_class_entry *zend_test_ns_foo_class; static zend_class_entry *zend_test_ns2_foo_class; static zend_class_entry *zend_test_ns2_ns_foo_class; @@ -552,6 +553,20 @@ static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override) RETURN_LONG(4); } +static ZEND_METHOD(ZendTestForbidDynamicCall, call) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_forbid_dynamic_call(); +} + +static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_forbid_dynamic_call(); +} + PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals) @@ -643,6 +658,8 @@ PHP_MINIT_FUNCTION(zend_test) ZVAL_PSTRING(&attr->args[0].value, "value4"); } + zend_test_forbid_dynamic_call = register_class_ZendTestForbidDynamicCall(); + zend_test_ns_foo_class = register_class_ZendTestNS_Foo(); zend_test_ns2_foo_class = register_class_ZendTestNS2_Foo(); zend_test_ns2_ns_foo_class = register_class_ZendTestNS2_ZendSubNS_Foo(); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index d58cea27dfc33..08122b6c02581 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -60,6 +60,11 @@ class ZendTestChildClassWithMethodWithParameterAttribute extends ZendTestClassWi public function override(string $parameter): int {} } + final class ZendTestForbidDynamicCall { + public function call(): void {} + public static function callStatic(): void {} + } + enum ZendTestUnitEnum { case Foo; case Bar; diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index d682b53755096..26ed9f72f78a3 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 71d8e1e6e5a997e9b443fbce4136d0025b67830b */ + * Stub hash: 2d42ea64a5114eae618a6dfb642c2640f568f5db */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -114,6 +114,10 @@ ZEND_END_ARG_INFO() #define arginfo_class_ZendTestChildClassWithMethodWithParameterAttribute_override arginfo_zend_test_parameter_with_attribute +#define arginfo_class_ZendTestForbidDynamicCall_call arginfo_zend_test_void_return + +#define arginfo_class_ZendTestForbidDynamicCall_callStatic arginfo_zend_test_void_return + #define arginfo_class_ZendTestNS_Foo_method arginfo_zend_test_void_return #define arginfo_class_ZendTestNS2_Foo_method arginfo_zend_test_void_return @@ -153,6 +157,8 @@ static ZEND_METHOD(ZendTestParameterAttribute, __construct); static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override); static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, override); static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override); +static ZEND_METHOD(ZendTestForbidDynamicCall, call); +static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic); static ZEND_METHOD(ZendTestNS_Foo, method); static ZEND_METHOD(ZendTestNS2_Foo, method); static ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo, method); @@ -235,6 +241,13 @@ static const zend_function_entry class_ZendTestChildClassWithMethodWithParameter }; +static const zend_function_entry class_ZendTestForbidDynamicCall_methods[] = { + ZEND_ME(ZendTestForbidDynamicCall, call, arginfo_class_ZendTestForbidDynamicCall_call, ZEND_ACC_PUBLIC) + ZEND_ME(ZendTestForbidDynamicCall, callStatic, arginfo_class_ZendTestForbidDynamicCall_callStatic, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_FE_END +}; + + static const zend_function_entry class_ZendTestUnitEnum_methods[] = { ZEND_FE_END }; @@ -408,6 +421,17 @@ static zend_class_entry *register_class_ZendTestChildClassWithMethodWithParamete return class_entry; } +static zend_class_entry *register_class_ZendTestForbidDynamicCall(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "ZendTestForbidDynamicCall", class_ZendTestForbidDynamicCall_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_FINAL; + + return class_entry; +} + static zend_class_entry *register_class_ZendTestUnitEnum(void) { zend_class_entry *class_entry = zend_register_internal_enum("ZendTestUnitEnum", IS_UNDEF, class_ZendTestUnitEnum_methods); diff --git a/ext/zend_test/tests/zend_forbid_dynamic_call.phpt b/ext/zend_test/tests/zend_forbid_dynamic_call.phpt new file mode 100644 index 0000000000000..77d8649f5322d --- /dev/null +++ b/ext/zend_test/tests/zend_forbid_dynamic_call.phpt @@ -0,0 +1,29 @@ +--TEST-- +Zend: Test zend_forbid_dynamic_call() for methods +--EXTENSIONS-- +zend_test +--FILE-- +call(); +ZendTestForbidDynamicCall::callStatic(); + +try { + $call = [$object, 'call']; + $call(); +} catch (Error $error) { + echo $error->getMessage(), "\n"; +} + +try { + $callStatic = [ZendTestForbidDynamicCall::class, 'callStatic']; + $callStatic(); +} catch (Error $error) { + echo $error->getMessage(), "\n"; +} + +?> +--EXPECT-- +Cannot call ZendTestForbidDynamicCall::call() dynamically +Cannot call ZendTestForbidDynamicCall::callStatic() dynamically