diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index e16a7bdae805..45c4ef34e852 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -40,6 +40,8 @@ PHP 8.7 INTERNALS UPGRADE NOTES - Added a new zend_object_copy() function which increases the refcount of a zend_object* and returns it. Allowing more descriptive code rather than doing an assignment followed by GC_ADDREF(). +- Added zend_call_method_if_exists_ex() which accepts named parameters and + retrieving the callability failure error message. ======================== 2. Build system changes diff --git a/Zend/zend_API.h b/Zend/zend_API.h index c94a71cf56b8..425139e3a00b 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -913,12 +913,21 @@ static zend_always_inline void zend_call_known_instance_method_with_1_params( ZEND_API void zend_call_known_instance_method_with_2_params( zend_function *fn, zend_object *this_ptr, zval *retval_ptr, zval *param1, zval *param2); -/* Call method if it exists. Return FAILURE if method does not exist or call failed. - * If FAILURE is returned, retval will be UNDEF. As such, destroying retval unconditionally - * is legal. */ -ZEND_API zend_result zend_call_method_if_exists( - zend_object *this_ptr, zend_string *method_name, zval *retval, - uint32_t param_count, zval *params); +/* Call method if it exists. + * Return FAILURE if method does not exist. + * If FAILURE is returned, retval will be UNDEF, and error will contain the validation failure message if provided. + * As such, destroying retval unconditionally is legal. + */ +ZEND_API zend_result zend_call_method_if_exists_ex( + zend_object *this_ptr, zend_string *method_name, zval *retval_ptr, + uint32_t param_count, zval *params, HashTable *named_params, char **error); + +static zend_always_inline zend_result zend_call_method_if_exists( + zend_object *this_ptr, zend_string *method_name, + zval *retval_ptr, uint32_t param_count, zval *params +) { + return zend_call_method_if_exists_ex(this_ptr, method_name, retval_ptr, param_count, params, NULL, NULL); +} ZEND_API zend_result zend_delete_global_variable(zend_string *name); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index a1b7c16ba73f..beb3f9f995af 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1184,21 +1184,21 @@ ZEND_API void zend_call_known_instance_method_with_2_params( zend_call_known_instance_method(fn, this_ptr, retval_ptr, 2, params); } -ZEND_API zend_result zend_call_method_if_exists( - zend_object *this_ptr, zend_string *method_name, zval *retval, - uint32_t param_count, zval *params) -{ +ZEND_API zend_result zend_call_method_if_exists_ex( + zend_object *this_ptr, zend_string *method_name, zval *retval_ptr, + uint32_t param_count, zval *params, HashTable *named_params, char **error +) { zval zval_method; zend_fcall_info_cache fcc; ZVAL_STR(&zval_method, method_name); - if (UNEXPECTED(!zend_is_callable_ex(&zval_method, this_ptr, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL))) { - ZVAL_UNDEF(retval); + if (UNEXPECTED(!zend_is_callable_ex(&zval_method, this_ptr, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, error))) { + ZVAL_UNDEF(retval_ptr); return FAILURE; } - zend_call_known_fcc(&fcc, retval, param_count, params, NULL); + zend_call_known_fcc(&fcc, retval_ptr, param_count, params, named_params); /* Need to free potential trampoline (__call/__callStatic) copied function handler before releasing the closure */ zend_release_fcall_info_cache(&fcc); return SUCCESS;