Commit 54b58d56085 for php.net

commit 54b58d56085fbb40a85060b5cfa34a5fb871fb32
Author: Weilin Du <weilindu@php.net>
Date:   Mon Aug 3 00:13:33 2026 +0800

    ext/intl: Refactor global error resets (#22990)

    Introduce PHP_INTL_FUNCTION_WITH_ERROR_RESET macro to standardize
    and automate the global Intl error state reset at the start of
    every userland PHP_FUNCTION. Also change the IC_METHOD function
    to automatically reset error state in the start of the defined function.

    The macro wraps the function entry point, performs
    intl_error_reset(NULL), and delegates the actual logic to a
    separate _impl function. This reduces boilerplate and prevents
    bugs caused by missing error resets, as seen in GH-22931 and
    GH-22500.

    This refactor applies to all functions with a manual reset call
    and does not affect internal helper functions that handle errors
    independently.

diff --git a/ext/intl/ERROR_CONVENTIONS.md b/ext/intl/ERROR_CONVENTIONS.md
index 5c1b4eca86b..0ecd8a0d0b8 100644
--- a/ext/intl/ERROR_CONVENTIONS.md
+++ b/ext/intl/ERROR_CONVENTIONS.md
@@ -93,13 +93,21 @@ void intl_error_reset(NULL);             /* reset global error */
 void intl_errors_reset(intl_error* err); /* reset global and object error */
 ```

-In practice, `intl_errors_reset()` is not used because most classes have also
-plain functions mapped to the same internal functions as their instance methods.
-Fetching of the object is done with `zend_parse_method_parameters()` instead of
-directly using `getThis()`. Therefore, no reference to object is obtained until
-the arguments are fully parsed. Without a reference to the object, there's no
-way to reset the object's internal error code. Instead, resetting of the
-object's internal error code is done upon fetching the object from its zval.
+Procedural functions that reset the global error should normally use
+`PHP_INTL_FUNCTION_WITH_ERROR_RESET(name)`, which resets the global error before
+entering the implementation body.
+Class-specific method helper macros may use the same pattern when all methods
+covered by the macro reset the global error.
+
+`intl_errors_reset()` may be used directly when the object is available before
+argument parsing, for example in methods that only operate on `ZEND_THIS()`.
+For classes that have plain functions mapped to the same internal functions as
+their instance methods, fetching of the object is done with
+`zend_parse_method_parameters()` instead of directly using `getThis()`.
+Therefore, no reference to object is obtained until the arguments are fully
+parsed. Without a reference to the object, there's no way to reset the object's
+internal error code. Instead, resetting of the object's internal error code is
+done upon fetching the object from its zval.

 Example:

diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp
index fcb2e56bb89..0c6e68a65e2 100644
--- a/ext/intl/calendar/calendar_methods.cpp
+++ b/ext/intl/calendar/calendar_methods.cpp
@@ -70,14 +70,13 @@ U_CFUNC PHP_METHOD(IntlCalendar, __construct)
 		0 );
 }

-U_CFUNC PHP_FUNCTION(intlcal_create_instance)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intlcal_create_instance)
 {
 	zend_object *timezone_object = nullptr;
 	zend_string *timezone_string = nullptr;
 	char	        *locale_str	= NULL;
 	size_t		locale_len      = 0;
 	UErrorCode	status			= U_ZERO_ERROR;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(0, 2)
 		Z_PARAM_OPTIONAL
@@ -158,7 +157,7 @@ private:
 };
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BugStringCharEnumeration)

-U_CFUNC PHP_FUNCTION(intlcal_get_keyword_values_for_locale)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intlcal_get_keyword_values_for_locale)
 {
 	UErrorCode	status = U_ZERO_ERROR;
 	char		*key,
@@ -166,7 +165,6 @@ U_CFUNC PHP_FUNCTION(intlcal_get_keyword_values_for_locale)
 	size_t			key_len,
 				locale_len;
 	bool	commonly_used;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(3, 3)
 		Z_PARAM_STRING(key, key_len)
@@ -186,19 +184,15 @@ U_CFUNC PHP_FUNCTION(intlcal_get_keyword_values_for_locale)
 	IntlIterator_from_StringEnumeration(se, return_value);
 }

-U_CFUNC PHP_FUNCTION(intlcal_get_now)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intlcal_get_now)
 {
-	intl_error_reset(NULL);
-
 	ZEND_PARSE_PARAMETERS_NONE();

 	RETURN_DOUBLE((double)Calendar::getNow());
 }

-U_CFUNC PHP_FUNCTION(intlcal_get_available_locales)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intlcal_get_available_locales)
 {
-	intl_error_reset(NULL);
-
 	ZEND_PARSE_PARAMETERS_NONE();

 	int32_t count;
@@ -1018,7 +1012,7 @@ U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option)
 	RETURN_TRUE;
 }

-U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intlcal_from_date_time)
 {
 	zend_object     *date_obj;
 	zend_string     *date_str;
@@ -1029,7 +1023,6 @@ U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
 	TimeZone		*timeZone;
 	UErrorCode		status = U_ZERO_ERROR;
 	Calendar        *cal;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_OBJ_OF_CLASS_OR_STR(date_obj, php_date_get_date_ce(), date_str)
diff --git a/ext/intl/locale/locale_methods.cpp b/ext/intl/locale/locale_methods.cpp
index 05ec5825d8c..87a08d96c62 100644
--- a/ext/intl/locale/locale_methods.cpp
+++ b/ext/intl/locale/locale_methods.cpp
@@ -836,7 +836,7 @@ U_CFUNC PHP_FUNCTION(locale_get_display_keyword_value)
  /* {{{ return an associative array containing keyword-value
  * pairs for this locale. The keys are keys to the array (doh!)
  */
-U_CFUNC PHP_FUNCTION( locale_get_keywords )
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_keywords)
 {
 	UEnumeration*   e        = NULL;
 	UErrorCode      status   = U_ZERO_ERROR;
@@ -847,7 +847,6 @@ U_CFUNC PHP_FUNCTION( locale_get_keywords )
 	char*       	        loc_name        = NULL;
 	size_t        	 	loc_name_len    = 0;

-	intl_error_reset( NULL );

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH(loc_name, loc_name_len)
@@ -1051,7 +1050,7 @@ static int handleAppendResult( int result, smart_str* loc_name)
 * }}} */
 /* {{{ Creates a locale by combining the parts of locale-ID passed
 * }}} */
-U_CFUNC PHP_FUNCTION(locale_compose)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_compose)
 {
 	smart_str      	loc_name_s = {NULL, 0};
 	smart_str *loc_name = &loc_name_s;
@@ -1059,7 +1058,6 @@ U_CFUNC PHP_FUNCTION(locale_compose)
 	HashTable*		hash_arr = NULL;
 	int 			result = 0;

-	intl_error_reset( NULL );

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_ARRAY(arr)
@@ -1232,13 +1230,12 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, const char* key
 /* }}} */

 /* {{{ parses a locale-id into an array the different parts of it */
-U_CFUNC PHP_FUNCTION(locale_parse)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_parse)
 {
 	char*          loc_name        = NULL;
 	size_t         loc_name_len    = 0;
 	int         grOffset    	= 0;

-	intl_error_reset( NULL );

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH(loc_name, loc_name_len)
@@ -1268,7 +1265,7 @@ U_CFUNC PHP_FUNCTION(locale_parse)
 /* }}} */

 /* {{{ gets an array containing the list of variants, or null */
-U_CFUNC PHP_FUNCTION(locale_get_all_variants)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_all_variants)
 {
 	char*  	                loc_name        = NULL;
 	size_t    		loc_name_len    = 0;
@@ -1278,7 +1275,6 @@ U_CFUNC PHP_FUNCTION(locale_get_all_variants)
 	zend_string*	variant		= NULL;
 	char*	saved_ptr	= NULL;

-	intl_error_reset( NULL );

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH(loc_name, loc_name_len)
@@ -1352,7 +1348,7 @@ static int strToMatch(const char* str ,char *retstr)
 /* {{{ Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm */
 /* }}} */
 /* {{{ Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm */
-U_CFUNC PHP_FUNCTION(locale_filter_matches)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_filter_matches)
 {
 	char*       	lang_tag        = NULL;
 	size_t         	lang_tag_len    = 0;
@@ -1372,7 +1368,6 @@ U_CFUNC PHP_FUNCTION(locale_filter_matches)
 	bool 	boolCanonical 	= 0;
 	UErrorCode	status		= U_ZERO_ERROR;

-	intl_error_reset( NULL );

 	ZEND_PARSE_PARAMETERS_START(2, 3)
 		Z_PARAM_PATH(lang_tag, lang_tag_len)
@@ -1640,7 +1635,7 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 /* {{{ Searches the items in $langtag for the best match to the language
 * range
 */
-U_CFUNC PHP_FUNCTION(locale_lookup)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_lookup)
 {
 	zend_string*   	fallback_loc_str	= NULL;
 	char*    	loc_range      		= NULL;
@@ -1651,7 +1646,6 @@ U_CFUNC PHP_FUNCTION(locale_lookup)
 	bool	boolCanonical	= 0;
 	zend_string* 	result_str	= NULL;

-	intl_error_reset( NULL );

 	ZEND_PARSE_PARAMETERS_START(2, 4)
 		Z_PARAM_ARRAY(arr)
diff --git a/ext/intl/normalizer/normalizer_normalize.cpp b/ext/intl/normalizer/normalizer_normalize.cpp
index e5b8db14baf..657ea6db1f4 100644
--- a/ext/intl/normalizer/normalizer_normalize.cpp
+++ b/ext/intl/normalizer/normalizer_normalize.cpp
@@ -73,7 +73,7 @@ static UBool intl_is_normalized(zend_long form, const UChar *uinput, int32_t uin
 }/*}}}*/

 /* {{{ Normalize a string. */
-U_CFUNC PHP_FUNCTION( normalizer_normalize )
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(normalizer_normalize)
 {
 	char*			input = NULL;
 	/* form is optional, defaults to FORM_C */
@@ -92,7 +92,6 @@ U_CFUNC PHP_FUNCTION( normalizer_normalize )

 	int32_t			size_needed;

-	intl_error_reset( NULL );

 	/* Parse parameters. */
 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "s|l",
@@ -202,7 +201,7 @@ U_CFUNC PHP_FUNCTION( normalizer_normalize )
 /* }}} */

 /* {{{ Test if a string is in a given normalization form. */
-U_CFUNC PHP_FUNCTION( normalizer_is_normalized )
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(normalizer_is_normalized)
 {
 	char*	 	input = NULL;
 	/* form is optional, defaults to FORM_C */
@@ -215,7 +214,6 @@ U_CFUNC PHP_FUNCTION( normalizer_is_normalized )

 	UBool		uret = false;

-	intl_error_reset( NULL );

 	/* Parse parameters. */
 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "s|l",
@@ -278,7 +276,7 @@ U_CFUNC PHP_FUNCTION( normalizer_is_normalized )
 /* }}} */

 /* {{{ Returns the Decomposition_Mapping property for the given UTF-8 encoded code point. */
-U_CFUNC PHP_FUNCTION( normalizer_get_raw_decomposition )
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(normalizer_get_raw_decomposition)
 {
 	char* input = NULL;
 	size_t input_length = 0;
@@ -293,7 +291,6 @@ U_CFUNC PHP_FUNCTION( normalizer_get_raw_decomposition )

 	zend_long form = NORMALIZER_DEFAULT;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STRING(input, input_length)
diff --git a/ext/intl/php_intl.h b/ext/intl/php_intl.h
index 6b6cce59b92..52f80d48e3a 100644
--- a/ext/intl/php_intl.h
+++ b/ext/intl/php_intl.h
@@ -71,6 +71,15 @@ PHP_MINFO_FUNCTION(intl);
 const char *intl_locale_get_default( void );
 char *canonicalize_locale_string(const char* locale);

+#define PHP_INTL_FUNCTION_WITH_ERROR_RESET(name) \
+	static void php_intl_##name##_impl(INTERNAL_FUNCTION_PARAMETERS); \
+	U_CFUNC PHP_FUNCTION(name) \
+	{ \
+		intl_error_reset(NULL); \
+		php_intl_##name##_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU); \
+	} \
+	static void php_intl_##name##_impl(INTERNAL_FUNCTION_PARAMETERS)
+
 #define PHP_INTL_VERSION PHP_VERSION

 #endif  /* PHP_INTL_H */
diff --git a/ext/intl/resourcebundle/resourcebundle_class.cpp b/ext/intl/resourcebundle/resourcebundle_class.cpp
index a997691f642..e5a0fe1eefc 100644
--- a/ext/intl/resourcebundle/resourcebundle_class.cpp
+++ b/ext/intl/resourcebundle/resourcebundle_class.cpp
@@ -333,7 +333,7 @@ U_CFUNC PHP_FUNCTION( resourcebundle_count )
 }

 /* {{{ Get available locales from ResourceBundle name */
-U_CFUNC PHP_FUNCTION( resourcebundle_locales )
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(resourcebundle_locales)
 {
 	char * bundlename;
 	size_t    bundlename_len = 0;
@@ -343,8 +343,6 @@ U_CFUNC PHP_FUNCTION( resourcebundle_locales )
 	UEnumeration *icuenum;
 	UErrorCode   icuerror = U_ZERO_ERROR;

-	intl_errors_reset( NULL );
-
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STRING(bundlename, bundlename_len)
 	ZEND_PARSE_PARAMETERS_END();
diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp
index c2246c5406b..118b153cc79 100644
--- a/ext/intl/timezone/timezone_methods.cpp
+++ b/ext/intl/timezone/timezone_methods.cpp
@@ -46,11 +46,10 @@ U_CFUNC PHP_METHOD(IntlTimeZone, __construct)
 		0 );
 }

-U_CFUNC PHP_FUNCTION(intltz_create_time_zone)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_create_time_zone)
 {
 	char	*str_id;
 	size_t	 str_id_len;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STRING(str_id, str_id_len)
@@ -69,12 +68,11 @@ U_CFUNC PHP_FUNCTION(intltz_create_time_zone)
 	timezone_object_construct(tz, return_value, 1);
 }

-U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_from_date_time_zone)
 {
 	zval				*zv_timezone;
 	TimeZone			*tz;
 	php_timezone_obj	*tzobj;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_OBJECT_OF_CLASS(zv_timezone, php_date_get_timezone_ce())
@@ -94,41 +92,34 @@ U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone)
 	timezone_object_construct(tz, return_value, 1);
 }

-U_CFUNC PHP_FUNCTION(intltz_create_default)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_create_default)
 {
-	intl_error_reset(NULL);
-
 	ZEND_PARSE_PARAMETERS_NONE();

 	TimeZone *tz = TimeZone::createDefault();
 	timezone_object_construct(tz, return_value, 1);
 }

-U_CFUNC PHP_FUNCTION(intltz_get_gmt)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_get_gmt)
 {
-	intl_error_reset(NULL);
-
 	ZEND_PARSE_PARAMETERS_NONE();

 	timezone_object_construct(TimeZone::getGMT(), return_value, 0);
 }

-U_CFUNC PHP_FUNCTION(intltz_get_unknown)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_get_unknown)
 {
-	intl_error_reset(NULL);
-
 	ZEND_PARSE_PARAMETERS_NONE();

 	timezone_object_construct(&TimeZone::getUnknown(), return_value, 0);
 }

-U_CFUNC PHP_FUNCTION(intltz_create_enumeration)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_create_enumeration)
 {
 	zend_string *timezone = nullptr;
 	zend_long timezone_shift = 0;
 	bool is_null = true;
 	StringEnumeration	*se	  = nullptr;
-	intl_error_reset(nullptr);

 	/* double indirection to have the zend engine destroy the new zval that
 	 * results from separation */
@@ -158,11 +149,10 @@ U_CFUNC PHP_FUNCTION(intltz_create_enumeration)
 	}
 }

-U_CFUNC PHP_FUNCTION(intltz_count_equivalent_ids)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_count_equivalent_ids)
 {
 	char	*str_id;
 	size_t	 str_id_len;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STRING(str_id, str_id_len)
@@ -180,7 +170,7 @@ U_CFUNC PHP_FUNCTION(intltz_count_equivalent_ids)
 	RETURN_LONG((zend_long)result);
 }

-U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_create_time_zone_id_enumeration)
 {
 	zend_long zoneType,
 			  offset_arg;
@@ -190,7 +180,6 @@ U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration)
 			 *offsetp	= NULL;
 	bool arg3isnull = 1;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 3)
 		Z_PARAM_LONG(zoneType)
@@ -224,12 +213,11 @@ U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration)
 	IntlIterator_from_StringEnumeration(se, return_value);
 }

-U_CFUNC PHP_FUNCTION(intltz_get_canonical_id)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_get_canonical_id)
 {
 	char	*str_id;
 	size_t	 str_id_len;
 	zval	*is_systemid = NULL;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STRING(str_id, str_id_len)
@@ -260,12 +248,11 @@ U_CFUNC PHP_FUNCTION(intltz_get_canonical_id)
 	}
 }

-U_CFUNC PHP_FUNCTION(intltz_get_region)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_get_region)
 {
 	char	*str_id;
 	size_t	 str_id_len;
 	char	 outbuf[3];
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STRING(str_id, str_id_len)
@@ -285,10 +272,8 @@ U_CFUNC PHP_FUNCTION(intltz_get_region)
 	RETURN_STRINGL(outbuf, region_len);
 }

-U_CFUNC PHP_FUNCTION(intltz_get_tz_data_version)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_get_tz_data_version)
 {
-	intl_error_reset(NULL);
-
 	ZEND_PARSE_PARAMETERS_NONE();

 	UErrorCode status = UErrorCode();
@@ -298,12 +283,11 @@ U_CFUNC PHP_FUNCTION(intltz_get_tz_data_version)
 	RETURN_STRING(res);
 }

-U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_get_equivalent_id)
 {
 	char	   *str_id;
 	size_t		str_id_len;
 	zend_long	index;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(2, 2)
 		Z_PARAM_STRING(str_id, str_id_len)
@@ -332,11 +316,10 @@ U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id)
 }

 #if U_ICU_VERSION_MAJOR_NUM >= 74
-U_CFUNC PHP_FUNCTION(intltz_get_iana_id)
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(intltz_get_iana_id)
 {
 	char	*str_id;
 	size_t	 str_id_len;
-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STRING(str_id, str_id_len)
diff --git a/ext/intl/transliterator/transliterator_methods.cpp b/ext/intl/transliterator/transliterator_methods.cpp
index 9cdec2611a2..d84fdbbe36a 100644
--- a/ext/intl/transliterator/transliterator_methods.cpp
+++ b/ext/intl/transliterator/transliterator_methods.cpp
@@ -223,7 +223,7 @@ U_CFUNC PHP_FUNCTION( transliterator_create_inverse )
 /* }}} */

 /* {{{ Return an array with the registered transliterator IDs. */
-U_CFUNC PHP_FUNCTION( transliterator_list_ids )
+PHP_INTL_FUNCTION_WITH_ERROR_RESET(transliterator_list_ids)
 {
 	UEnumeration  *en;
 	const UChar	  *elem;
@@ -231,8 +231,6 @@ U_CFUNC PHP_FUNCTION( transliterator_list_ids )
 	int32_t		  count;
 	UErrorCode	  status = U_ZERO_ERROR;

-	intl_error_reset( nullptr );
-
 	ZEND_PARSE_PARAMETERS_NONE();

 	en = utrans_openIDs( &status );
diff --git a/ext/intl/uchar/uchar.cpp b/ext/intl/uchar/uchar.cpp
index 80bdd2bdb9f..89bc0a31733 100644
--- a/ext/intl/uchar/uchar.cpp
+++ b/ext/intl/uchar/uchar.cpp
@@ -23,7 +23,14 @@ extern "C" {
 #include "uchar_arginfo.h"
 }

-#define IC_METHOD(mname) PHP_METHOD(IntlChar, mname)
+#define IC_METHOD(mname) \
+static void php_intl_IntlChar_##mname##_impl(INTERNAL_FUNCTION_PARAMETERS); \
+PHP_METHOD(IntlChar, mname) \
+{ \
+	intl_error_reset(NULL); \
+	php_intl_IntlChar_##mname##_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU); \
+} \
+static void php_intl_IntlChar_##mname##_impl(INTERNAL_FUNCTION_PARAMETERS)

 static inline int convert_cp(UChar32* pcp, const zend_string *string_codepoint, zend_long int_codepoint) {
 	if (string_codepoint != NULL) {
@@ -70,7 +77,6 @@ IC_METHOD(chr) {
 	char buffer[5];
 	int buffer_len = 0;

-	intl_error_reset(NULL);

 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
@@ -91,7 +97,6 @@ IC_METHOD(chr) {
 IC_METHOD(ord) {
 	UChar32 cp;

-	intl_error_reset(NULL);

 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
@@ -108,7 +113,6 @@ IC_METHOD(hasBinaryProperty) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(2, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
@@ -130,7 +134,6 @@ IC_METHOD(getIntPropertyValue) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(2, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
@@ -149,7 +152,6 @@ IC_METHOD(getIntPropertyValue) {
 IC_METHOD(getIntPropertyMinValue) {
 	zend_long prop;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_LONG(prop)
@@ -163,7 +165,6 @@ IC_METHOD(getIntPropertyMinValue) {
 IC_METHOD(getIntPropertyMaxValue) {
 	zend_long prop;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_LONG(prop)
@@ -177,7 +178,6 @@ IC_METHOD(getIntPropertyMaxValue) {
 IC_METHOD(getNumericValue) {
 	UChar32 cp;

-	intl_error_reset(NULL);

 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
@@ -221,7 +221,6 @@ static UBool enumCharType_callback(enumCharType_data *context,
 IC_METHOD(enumCharTypes) {
 	enumCharType_data context;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_FUNC(context.fci, context.fci_cache)
@@ -234,7 +233,6 @@ IC_METHOD(enumCharTypes) {
 IC_METHOD(getBlockCode) {
 	UChar32 cp;

-	intl_error_reset(NULL);

 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
@@ -254,7 +252,6 @@ IC_METHOD(charName) {
 	zend_string *buffer = NULL;
 	int32_t buffer_len;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
@@ -286,7 +283,6 @@ IC_METHOD(charFromName) {
 	UChar32 ret;
 	UErrorCode error = U_ZERO_ERROR;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STRING(name, name_len)
@@ -339,7 +335,6 @@ IC_METHOD(enumCharNames) {
 	zend_long nameChoice = U_UNICODE_CHAR_NAME;
 	UErrorCode error = U_ZERO_ERROR;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(3, 4)
 		Z_PARAM_STR_OR_LONG(string_start, int_start)
@@ -365,7 +360,6 @@ IC_METHOD(getPropertyName) {
 	zend_long nameChoice = U_LONG_PROPERTY_NAME;
 	const char *ret;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_LONG(property)
@@ -389,7 +383,6 @@ IC_METHOD(getPropertyEnum) {
 	char *alias;
 	size_t alias_len;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STRING(alias, alias_len)
@@ -404,7 +397,6 @@ IC_METHOD(getPropertyValueName) {
 	zend_long property, value, nameChoice = U_LONG_PROPERTY_NAME;
 	const char *ret;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(2, 3)
 		Z_PARAM_LONG(property)
@@ -430,7 +422,6 @@ IC_METHOD(getPropertyValueEnum) {
 	char *name;
 	size_t name_len;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(2, 2)
 		Z_PARAM_LONG(property)
@@ -448,7 +439,6 @@ IC_METHOD(foldCase) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
@@ -481,7 +471,6 @@ IC_METHOD(digit) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
@@ -507,7 +496,6 @@ IC_METHOD(digit) {
 IC_METHOD(forDigit) {
 	zend_long digit, radix = 10;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_LONG(digit)
@@ -525,7 +513,6 @@ IC_METHOD(charAge) {
 	UVersionInfo version;
 	int i;

-	intl_error_reset(NULL);

 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
@@ -544,7 +531,6 @@ IC_METHOD(getUnicodeVersion) {
 	UVersionInfo version;
 	int i;

-	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_NONE();

@@ -564,7 +550,6 @@ IC_METHOD(getFC_NFKC_Closure) {
 	int32_t closure_len;
 	UErrorCode error = U_ZERO_ERROR;

-	intl_error_reset(NULL);

 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
@@ -594,7 +579,6 @@ IC_METHOD(getFC_NFKC_Closure) {
 #define IC_BOOL_METHOD_CHAR(name) \
 IC_METHOD(name) { \
 	UChar32 cp; \
-	intl_error_reset(NULL); \
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) { \
 		RETURN_NULL(); \
 	} \
@@ -635,7 +619,6 @@ IC_BOOL_METHOD_CHAR(isJavaIDPart)
 #define IC_INT_METHOD_CHAR(name) \
 IC_METHOD(name) { \
 	UChar32 cp; \
-	intl_error_reset(NULL); \
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) { \
 		RETURN_NULL(); \
 	} \
@@ -656,7 +639,6 @@ IC_METHOD(name) { \
 	UChar32 cp, ret; \
 	zend_string *string_codepoint; \
 		zend_long int_codepoint = -1; \
-		intl_error_reset(NULL); \
 		ZEND_PARSE_PARAMETERS_START(1, 1) \
 			Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint) \
 		ZEND_PARSE_PARAMETERS_END(); \