diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 14aad0d1a32..bbf9d68fb21 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -514,6 +514,28 @@ static ZEND_FUNCTION(zend_object_init_with_constructor) ZVAL_COPY_VALUE(return_value, &obj); } +static ZEND_FUNCTION(zend_call_method_if_exists) +{ + zend_object *obj = NULL; + zend_string *method_name; + uint32_t num_args = 0; + zval *args = NULL; + ZEND_PARSE_PARAMETERS_START(2, -1) + Z_PARAM_OBJ(obj) + Z_PARAM_STR(method_name) + Z_PARAM_VARIADIC('*', args, num_args) + ZEND_PARSE_PARAMETERS_END(); + + zend_result status = zend_call_method_if_exists(obj, method_name, return_value, num_args, args); + if (status == FAILURE) { + ZEND_ASSERT(Z_ISUNDEF_P(return_value)); + if (EG(exception)) { + RETURN_THROWS(); + } + RETURN_NULL(); + } +} + static ZEND_FUNCTION(zend_get_unit_enum) { ZEND_PARSE_PARAMETERS_NONE(); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 528ec71ae7a..88ef73786cd 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -293,6 +293,8 @@ namespace { function zend_object_init_with_constructor(string $class, mixed ...$args): mixed {} + function zend_call_method_if_exists(object $obj, string $method, mixed ...$args): mixed {} + function zend_test_zend_ini_parse_quantity(string $str): int {} function zend_test_zend_ini_parse_uquantity(string $str): int {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index a00c5df7876..ac04ba20950 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: 13a5559e87cb073c921006bb3be5354b90247306 */ + * Stub hash: 073039fa0d9c41eb842f6944eb4acfc9217103cf */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -113,6 +113,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_object_init_with_constructo ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_call_method_if_exists, 0, 2, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, obj, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, method, IS_STRING, 0) + ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_zend_ini_parse_quantity, 0, 1, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -293,6 +299,7 @@ static ZEND_FUNCTION(zend_test_attribute_with_named_argument); static ZEND_FUNCTION(zend_get_current_func_name); static ZEND_FUNCTION(zend_call_method); static ZEND_FUNCTION(zend_object_init_with_constructor); +static ZEND_FUNCTION(zend_call_method_if_exists); static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity); static ZEND_FUNCTION(zend_test_zend_ini_parse_uquantity); static ZEND_FUNCTION(zend_test_zend_ini_str); @@ -419,6 +426,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_get_current_func_name, arginfo_zend_get_current_func_name) ZEND_FE(zend_call_method, arginfo_zend_call_method) ZEND_FE(zend_object_init_with_constructor, arginfo_zend_object_init_with_constructor) + ZEND_FE(zend_call_method_if_exists, arginfo_zend_call_method_if_exists) ZEND_FE(zend_test_zend_ini_parse_quantity, arginfo_zend_test_zend_ini_parse_quantity) ZEND_FE(zend_test_zend_ini_parse_uquantity, arginfo_zend_test_zend_ini_parse_uquantity) ZEND_FE(zend_test_zend_ini_str, arginfo_zend_test_zend_ini_str) diff --git a/ext/zend_test/tests/zend_call_method_if_exists/existing-non-public-methods.phpt b/ext/zend_test/tests/zend_call_method_if_exists/existing-non-public-methods.phpt new file mode 100644 index 00000000000..cb65aadcfbb --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/existing-non-public-methods.phpt @@ -0,0 +1,27 @@ +--TEST-- +zend_call_method_if_exists() with existing non public methods +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +NULL +NULL diff --git a/ext/zend_test/tests/zend_call_method_if_exists/existing-private-methods-within-scope.phpt b/ext/zend_test/tests/zend_call_method_if_exists/existing-private-methods-within-scope.phpt new file mode 100644 index 00000000000..a1677b353b2 --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/existing-private-methods-within-scope.phpt @@ -0,0 +1,23 @@ +--TEST-- +zend_call_method_if_exists() with existing public method +--EXTENSIONS-- +zend_test +--FILE-- +priv() + zend_call_method_if_exists($this, 'priv'); + } +} + +$c = new C(); +$c->test(); + +?> +--EXPECT-- +string(7) "C::priv" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/existing-public-methods.phpt b/ext/zend_test/tests/zend_call_method_if_exists/existing-public-methods.phpt new file mode 100644 index 00000000000..c9bbd8cd13b --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/existing-public-methods.phpt @@ -0,0 +1,21 @@ +--TEST-- +zend_call_method_if_exists() with existing public method +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(6) "A::foo" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/existing-static-non-public-methods.phpt b/ext/zend_test/tests/zend_call_method_if_exists/existing-static-non-public-methods.phpt new file mode 100644 index 00000000000..a08124a4420 --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/existing-static-non-public-methods.phpt @@ -0,0 +1,27 @@ +--TEST-- +zend_call_method_if_exists() with existing non public static methods +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +NULL +NULL diff --git a/ext/zend_test/tests/zend_call_method_if_exists/existing-static-public-methods.phpt b/ext/zend_test/tests/zend_call_method_if_exists/existing-static-public-methods.phpt new file mode 100644 index 00000000000..cc879a5b1aa --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/existing-static-public-methods.phpt @@ -0,0 +1,21 @@ +--TEST-- +zend_call_method_if_exists() with existing static public method +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(6) "A::foo" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/extended-non-existing-method-with-trampoline.phpt b/ext/zend_test/tests/zend_call_method_if_exists/extended-non-existing-method-with-trampoline.phpt new file mode 100644 index 00000000000..fea9bc79028 --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/extended-non-existing-method-with-trampoline.phpt @@ -0,0 +1,27 @@ +--TEST-- +zend_call_method_if_exists() with non existing method on extended class with a trampoline +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(24) "In B trampoline for bar!" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/extended-non-existing-method-with-trampoline2.phpt b/ext/zend_test/tests/zend_call_method_if_exists/extended-non-existing-method-with-trampoline2.phpt new file mode 100644 index 00000000000..41092d22521 --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/extended-non-existing-method-with-trampoline2.phpt @@ -0,0 +1,23 @@ +--TEST-- +zend_call_method_if_exists() with non existing method on extended class with a trampoline +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(24) "In A trampoline for bar!" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/method-throws-exception.phpt b/ext/zend_test/tests/zend_call_method_if_exists/method-throws-exception.phpt new file mode 100644 index 00000000000..f70e160042b --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/method-throws-exception.phpt @@ -0,0 +1,25 @@ +--TEST-- +zend_call_method_if_exists() with throwing method +--EXTENSIONS-- +zend_test +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Exception: Error diff --git a/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-both-trampoline.phpt b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-both-trampoline.phpt new file mode 100644 index 00000000000..d2f3d0fa30a --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-both-trampoline.phpt @@ -0,0 +1,44 @@ +--TEST-- +zend_call_method_if_exists() with non existing method on class with a trampoline and static trampoline +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(24) "In A trampoline for bar!" +string(24) "In B trampoline for bar!" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-static-trampoline.phpt b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-static-trampoline.phpt new file mode 100644 index 00000000000..3b111b14ea2 --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-static-trampoline.phpt @@ -0,0 +1,24 @@ +--TEST-- +zend_call_method_if_exists() with non existing method on class with a static trampoline +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +NULL diff --git a/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-trampoline.phpt b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-trampoline.phpt new file mode 100644 index 00000000000..335c1a2d00c --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-method-with-trampoline.phpt @@ -0,0 +1,24 @@ +--TEST-- +zend_call_method_if_exists() with non existing method on class with a trampoline +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(22) "In trampoline for bar!" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/non-existing-methods.phpt b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-methods.phpt new file mode 100644 index 00000000000..2c570b35c81 --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/non-existing-methods.phpt @@ -0,0 +1,21 @@ +--TEST-- +zend_call_method_if_exists() with non existing method +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +NULL diff --git a/ext/zend_test/tests/zend_call_method_if_exists/shadowing-private-method-with-trampoline.phpt b/ext/zend_test/tests/zend_call_method_if_exists/shadowing-private-method-with-trampoline.phpt new file mode 100644 index 00000000000..459947c996e --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/shadowing-private-method-with-trampoline.phpt @@ -0,0 +1,24 @@ +--TEST-- +zend_call_method_if_exists() shadowing a private method +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(22) "In trampoline for foo!" diff --git a/ext/zend_test/tests/zend_call_method_if_exists/shadowing-private-method.phpt b/ext/zend_test/tests/zend_call_method_if_exists/shadowing-private-method.phpt new file mode 100644 index 00000000000..5f4e0ce222e --- /dev/null +++ b/ext/zend_test/tests/zend_call_method_if_exists/shadowing-private-method.phpt @@ -0,0 +1,27 @@ +--TEST-- +zend_call_method_if_exists() shadowing a private method +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(6) "B::foo"