[PHP-CVS] [php-src] master: ext/intl: get_icu_value_internal() to reduce manual memory manageme… (#19433)

[email protected] (David CARLIER via GitHub) Mon, 3 Aug 2026 19:01:11 +0000
Newsgroups php.cvs
Message-ID <[email protected]>
Author: David CARLIER (devnexen)
Committer: GitHub (web-flow)
Pusher: devnexen
Date: 2026-08-03T20:01:08+01:00

Commit: https://github.com/php/php-src/commit/0920f2a251640761785c70a39f8ed0c4959a08cc
Raw diff: https://github.com/php/php-src/commit/0920f2a251640761785c70a39f8ed0c4959a08cc.diff

ext/intl: get_icu_value_internal() to reduce manual memory manageme… (#19433)

Changed paths:
  M  ext/intl/locale/locale_methods.cpp


Diff:

diff --git a/ext/intl/locale/locale_methods.cpp b/ext/intl/locale/locale_methods.cpp
index 87a08d96c62e..bb4cd1236497 100644
--- a/ext/intl/locale/locale_methods.cpp
+++ b/ext/intl/locale/locale_methods.cpp
@@ -16,6 +16,8 @@
 #include <config.h>
 #endif
 
+#include <memory>
+
 #include <unicode/ustring.h>
 #include <unicode/udata.h>
 #include <unicode/putil.h>
@@ -116,7 +118,7 @@ static const char * const LOC_GRANDFATHERED[] = {
 	"zh-min-nan",
 	"zh-wuu",
 	"zh-xiang",
-	NULL
+	nullptr
 };
 
 /* Based on the IANA language subtag registry (File-Date: 2021-08-06)
@@ -125,20 +127,20 @@ static const char * const LOC_GRANDFATHERED[] = {
  * tags listed in LOC_GRANDFATHERED. This is in sync with the array
  * LOC_GRANDFATHERED, i.e., the offsets of the grandfathered tags match the
  * offsets of the preferred value. If a value in LOC_PREFERRED_GRANDFATHERED is
- * NULL, then the matching offset in LOC_GRANDFATHERED has no preferred value.
+ * nullptr, then the matching offset in LOC_GRANDFATHERED has no preferred value.
  */
 static const char * const LOC_PREFERRED_GRANDFATHERED[] = {
 	"jbo",
-	NULL,
+	nullptr,
 	"en-GB-oxendict",
 	"ami",
 	"bnn",
-	NULL,
-	NULL,
+	nullptr,
+	nullptr,
 	"hak",
 	"tlh",
 	"lb",
-	NULL,
+	nullptr,
 	"nv",
 	"pwn",
 	"tao",
@@ -174,11 +176,17 @@ static const char * const LOC_PREFERRED_GRANDFATHERED[] = {
 	"gan",
 	"cmn",
 	"hak",
-	NULL,
+	nullptr,
 	"nan",
 	"wuu",
 	"hsn",
-	NULL
+	nullptr
+};
+
+struct char_deleter {
+	void operator()(void *p) const {
+		efree(p);
+	}
 };
 
 /* returns true if a is an ID separator, false otherwise */
@@ -202,7 +210,7 @@ static const char * const LOC_PREFERRED_GRANDFATHERED[] = {
 static int16_t findOffset(const char* const* list, const char* key)
 {
 	const char* const* anchor = list;
-	while (*list != NULL) {
+	while (*list != nullptr) {
 		if (strcasecmp(key, *list) == 0) {
 			return (int16_t)(list - anchor);
 		}
@@ -216,14 +224,14 @@ static int16_t findOffset(const char* const* list, const char* key)
 
 static char* getPreferredTag(const char* gf_tag)
 {
-	char* result = NULL;
+	char* result = nullptr;
 	zend_off_t grOffset = 0;
 
 	grOffset = findOffset( LOC_GRANDFATHERED ,gf_tag);
 	if(grOffset < 0) {
-		return NULL;
+		return nullptr;
 	}
-	if( LOC_PREFERRED_GRANDFATHERED[grOffset] != NULL ){
+	if( LOC_PREFERRED_GRANDFATHERED[grOffset] != nullptr ){
 		/* return preferred tag */
 		result = estrdup( LOC_PREFERRED_GRANDFATHERED[grOffset] );
 	} else {
@@ -316,7 +324,7 @@ U_CFUNC PHP_NAMED_FUNCTION(zif_locale_set_default)
 {
 	zend_string* locale_name;
 	zend_string *ini_name;
-	char *default_locale = NULL;
+	char *default_locale = nullptr;
 
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH_STR(locale_name)
@@ -330,7 +338,7 @@ U_CFUNC PHP_NAMED_FUNCTION(zif_locale_set_default)
 	ini_name = zend_string_init(LOCALE_INI_NAME, sizeof(LOCALE_INI_NAME) - 1, 0);
 	zend_alter_ini_entry(ini_name, locale_name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 	zend_string_release_ex(ini_name, 0);
-	if (default_locale != NULL) {
+	if (default_locale != nullptr) {
 		zend_string_release_ex(locale_name, 0);
 	}
 
@@ -345,16 +353,16 @@ U_CFUNC PHP_NAMED_FUNCTION(zif_locale_set_default)
 */
 static zend_string* get_icu_value_internal( const char* loc_name , const char* tag_name, int* result , int fromParseLocale)
 {
-	zend_string* tag_value	    = NULL;
+	zend_string* tag_value	    = nullptr;
 	int32_t      tag_value_len  = 512;
 
-	char*        mod_loc_name   = NULL;
+	char*        mod_loc_name   = nullptr;
 
 	int32_t      buflen         = 512;
 	UErrorCode   status         = U_ZERO_ERROR;
 
 	if (UNEXPECTED(strlen(loc_name) > INTL_MAX_LOCALE_LEN)) {
-		return NULL;
+		return nullptr;
 	}
 
 	if( strcmp(tag_name, LOC_CANONICALIZE_TAG) != 0 ){
@@ -364,8 +372,8 @@ static zend_string* get_icu_value_internal( const char* loc_name , const char* t
 			if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
 				return zend_string_init(loc_name, strlen(loc_name), 0);
 			} else {
-				/* Since Grandfathered , no value , do nothing , return NULL */
-				return NULL;
+				/* Since Grandfathered , no value , do nothing , return nullptr */
+				return nullptr;
 			}
 		}
 
@@ -383,7 +391,7 @@ static zend_string* get_icu_value_internal( const char* loc_name , const char* t
 		if( singletonPos == 0){
 			/* singleton at start of script, region , variant etc.
 			 * or invalid singleton at start of language */
-			return NULL;
+			return nullptr;
 		} else if( singletonPos > 0 ){
 			/* singleton at some position except at start
 			 * strip off the singleton and rest of the loc_name */
@@ -393,7 +401,7 @@ static zend_string* get_icu_value_internal( const char* loc_name , const char* t
 
 	} /* end of if != LOC_CANONICAL_TAG */
 
-	if( mod_loc_name == NULL){
+	if( mod_loc_name == nullptr){
 		mod_loc_name = estrdup(loc_name );
 	}
 
@@ -437,7 +445,7 @@ static zend_string* get_icu_value_internal( const char* loc_name , const char* t
 			if( mod_loc_name ){
 				efree( mod_loc_name);
 			}
-			return NULL;
+			return nullptr;
 		}
 	} while( buflen > tag_value_len );
 
@@ -450,7 +458,7 @@ static zend_string* get_icu_value_internal( const char* loc_name , const char* t
 		if( mod_loc_name ){
 			efree( mod_loc_name);
 		}
-		return NULL;
+		return nullptr;
 	} else {
 		*result = 1;
 	}
@@ -471,17 +479,17 @@ static zend_string* get_icu_value_internal( const char* loc_name , const char* t
 static void get_icu_value_src_php( const char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
 {
 
-	char*          loc_name        	= NULL;
+	char*          loc_name        	= nullptr;
 	size_t         loc_name_len    	= 0;
 
-	zend_string*   tag_value		= NULL;
+	zend_string*   tag_value		= nullptr;
 
 	int         result    		= 0;
-	char*       msg        		= NULL;
+	char*       msg        		= nullptr;
 
 	UErrorCode  status          	= U_ZERO_ERROR;
 
-	intl_error_reset( NULL );
+	intl_error_reset( nullptr );
 
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH(loc_name, loc_name_len)
@@ -513,7 +521,7 @@ static void get_icu_value_src_php( const char* tag_name, INTERNAL_FUNCTION_PARAM
 	/* Error encountered while fetching the value */
 	if( result ==0) {
 		spprintf(&msg , 0, "unable to get locale %s", tag_name );
-		intl_error_set( NULL, status, msg);
+		intl_error_set( nullptr, status, msg);
 		efree(msg);
 		RETURN_NULL();
 	}
@@ -548,26 +556,26 @@ U_CFUNC PHP_FUNCTION(locale_get_primary_language )
  }}} */
 static void get_icu_disp_value_src_php( const char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
 {
-	char*          loc_name        	= NULL;
+	char*          loc_name        	= nullptr;
 	size_t         loc_name_len    	= 0;
 
-	char*       disp_loc_name       = NULL;
+	char*       disp_loc_name       = nullptr;
 	size_t      disp_loc_name_len   = 0;
 	int         free_loc_name       = 0;
 
-	UChar*      disp_name      	= NULL;
+	std::unique_ptr<UChar, char_deleter> disp_name;
 	int32_t     disp_name_len  	= 0;
 
-	char*       mod_loc_name        = NULL;
+	std::unique_ptr<char, char_deleter> mod_loc_name;
 
 	int32_t     buflen          	= 512;
 	UErrorCode  status          	= U_ZERO_ERROR;
 
 	zend_string* u8str;
 
-	char*       msg             	= NULL;
+	char*       msg             	= nullptr;
 
-	intl_error_reset( NULL );
+	intl_error_reset( nullptr );
 
 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_PATH(loc_name, loc_name_len)
@@ -577,7 +585,7 @@ static void get_icu_disp_value_src_php( const char* tag_name, INTERNAL_FUNCTION_
 
 	if (UNEXPECTED(loc_name_len > ULOC_FULLNAME_CAPACITY)) {
 		/* See bug 67397: overlong locale names cause trouble in uloc_getDisplayName */
-		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,  "name too long");
+		intl_error_set( nullptr, U_ILLEGAL_ARGUMENT_ERROR,  "name too long");
 		RETURN_FALSE;
 	}
 
@@ -590,16 +598,16 @@ static void get_icu_disp_value_src_php( const char* tag_name, INTERNAL_FUNCTION_
 		int grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
 		if( grOffset >= 0 ){
 			if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
-				mod_loc_name = getPreferredTag( loc_name );
+				mod_loc_name = std::unique_ptr<char, char_deleter>(getPreferredTag( loc_name ));
 			} else {
-				/* Since Grandfathered, no value, do nothing, return NULL */
+				/* Since Grandfathered, no value, do nothing, return nullptr */
 				RETURN_FALSE;
 			}
 		}
 	} /* end of if != LOC_CANONICAL_TAG */
 
-	if( mod_loc_name==NULL ){
-		mod_loc_name = estrdup( loc_name );
+	if( mod_loc_name==nullptr ){
+		mod_loc_name = std::unique_ptr<char, char_deleter>(estrdup( loc_name ));
 	}
 
 	/* Check if disp_loc_name passed , if not use default locale */
@@ -610,19 +618,23 @@ static void get_icu_disp_value_src_php( const char* tag_name, INTERNAL_FUNCTION_
 
 	/* Get the disp_value for the given locale */
 	do{
-		disp_name = reinterpret_cast<UChar *>(erealloc( disp_name , buflen * sizeof(UChar)  ));
+		auto tmp = reinterpret_cast<UChar *>(erealloc( disp_name.release() , buflen * sizeof(UChar)  ));
+		disp_name.reset(tmp);
 		disp_name_len = buflen;
 
+		auto p_mod_loc_name = mod_loc_name.get();
+		auto p_disp_name = disp_name.get();
+
 		if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
-			buflen = uloc_getDisplayLanguage ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
+			buflen = uloc_getDisplayLanguage ( p_mod_loc_name , disp_loc_name , p_disp_name , disp_name_len , &status);
 		} else if( strcmp(tag_name , LOC_SCRIPT_TAG)==0 ){
-			buflen = uloc_getDisplayScript ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
+			buflen = uloc_getDisplayScript ( p_mod_loc_name , disp_loc_name , p_disp_name , disp_name_len , &status);
 		} else if( strcmp(tag_name , LOC_REGION_TAG)==0 ){
-			buflen = uloc_getDisplayCountry ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
+			buflen = uloc_getDisplayCountry ( p_mod_loc_name , disp_loc_name , p_disp_name , disp_name_len , &status);
 		} else if( strcmp(tag_name , LOC_VARIANT_TAG)==0 ){
-			buflen = uloc_getDisplayVariant ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
+			buflen = uloc_getDisplayVariant ( p_mod_loc_name , disp_loc_name , p_disp_name , disp_name_len , &status);
 		} else if( strcmp(tag_name , DISP_NAME)==0 ){
-			buflen = uloc_getDisplayName ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
+			buflen = uloc_getDisplayName ( p_mod_loc_name , disp_loc_name , p_disp_name , disp_name_len , &status);
 		}
 
 		/* U_STRING_NOT_TERMINATED_WARNING is admissible here; don't look for it */
@@ -635,36 +647,26 @@ static void get_icu_disp_value_src_php( const char* tag_name, INTERNAL_FUNCTION_
 			}
 
 			spprintf(&msg, 0, "unable to get locale %s", tag_name );
-			intl_error_set( NULL, status, msg);
+			intl_error_set( nullptr, status, msg);
 			efree(msg);
-			if( disp_name){
-				efree( disp_name );
-			}
-			if( mod_loc_name){
-				efree( mod_loc_name );
-			}
 			if (free_loc_name) {
 				efree((void *)disp_loc_name);
-				disp_loc_name = NULL;
+				disp_loc_name = nullptr;
 			}
 			RETURN_FALSE;
 		}
 	} while( buflen > disp_name_len );
 
-	if( mod_loc_name){
-		efree( mod_loc_name );
-	}
 	if (free_loc_name) {
 		efree((void *)disp_loc_name);
-		disp_loc_name = NULL;
+		disp_loc_name = nullptr;
 	}
 	/* Convert display locale name from UTF-16 to UTF-8. */
-	u8str = intl_convert_utf16_to_utf8(disp_name, buflen, &status );
-	efree( disp_name );
+	u8str = intl_convert_utf16_to_utf8(disp_name.get(), buflen, &status );
 	if( !u8str )
 	{
 		spprintf(&msg, 0, "error converting display name for %s to UTF-8", tag_name );
-		intl_error_set( NULL, status, msg);
+		intl_error_set( nullptr, status, msg);
 		efree(msg);
 		RETURN_FALSE;
 	}
@@ -678,23 +680,23 @@ static void get_icu_disp_value_src_php( const char* tag_name, INTERNAL_FUNCTION_
  }}} */
 static void get_icu_disp_keyword_value_src_php(const char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
 {
-	char*       loc_name            = NULL;
+	char*       loc_name            = nullptr;
 	size_t      loc_name_len        = 0;
-	char*       keyword_name        = NULL;
+	char*       keyword_name        = nullptr;
 	size_t      keyword_name_len    = 0;
-	char*       disp_loc_name       = NULL;
+	char*       disp_loc_name       = nullptr;
 	size_t      disp_loc_name_len   = 0;
 	int         free_loc_name       = 0;
 
-	UChar*      disp_name           = NULL;
+	UChar*      disp_name           = nullptr;
 	int32_t     disp_name_len       = 0;
 	int32_t     buflen              = 512;
 	UErrorCode  status              = U_ZERO_ERROR;
 
 	zend_string* u8str;
-	char*       msg                 = NULL;
+	char*       msg                 = nullptr;
 
-	intl_error_reset( NULL );
+	intl_error_reset( nullptr );
 
 	if (strcmp(tag_name, DISP_KEYWORD) == 0) {
 		ZEND_PARSE_PARAMETERS_START(1, 2)
@@ -711,7 +713,7 @@ static void get_icu_disp_keyword_value_src_php(const char* tag_name, INTERNAL_FU
 		ZEND_PARSE_PARAMETERS_END();
 
 		if (UNEXPECTED(loc_name_len > ULOC_FULLNAME_CAPACITY)) {
-			intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "name too long");
+			intl_error_set( nullptr, U_ILLEGAL_ARGUMENT_ERROR, "name too long");
 			RETURN_FALSE;
 		}
 
@@ -743,14 +745,14 @@ static void get_icu_disp_keyword_value_src_php(const char* tag_name, INTERNAL_FU
 			}
 
 			spprintf(&msg, 0, "unable to get locale %s", tag_name);
-			intl_error_set( NULL, status, msg);
+			intl_error_set( nullptr, status, msg);
 			efree(msg);
 			if (disp_name) {
 				efree(disp_name);
 			}
 			if (free_loc_name) {
 				efree((void *)disp_loc_name);
-				disp_loc_name = NULL;
+				disp_loc_name = nullptr;
 			}
 			RETURN_FALSE;
 		}
@@ -758,14 +760,14 @@ static void get_icu_disp_keyword_value_src_php(const char* tag_name, INTERNAL_FU
 
 	if (free_loc_name) {
 		efree((void *)disp_loc_name);
-		disp_loc_name = NULL;
+		disp_loc_name = nullptr;
 	}
 
 	u8str = intl_convert_utf16_to_utf8(disp_name, buflen, &status);
 	efree(disp_name);
 	if (!u8str) {
 		spprintf(&msg, 0, "error converting display name for %s to UTF-8", tag_name);
-		intl_error_set( NULL, status, msg);
+		intl_error_set( nullptr, status, msg);
 		efree(msg);
 		RETURN_FALSE;
 	}
@@ -838,16 +840,15 @@ U_CFUNC PHP_FUNCTION(locale_get_display_keyword_value)
  */
 PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_keywords)
 {
-	UEnumeration*   e        = NULL;
+	UEnumeration*   e        = nullptr;
 	UErrorCode      status   = U_ZERO_ERROR;
 
-	const char*	 	kw_key        = NULL;
+	const char*	 	kw_key        = nullptr;
 	int32_t         kw_key_len    = 0;
 
-	char*       	        loc_name        = NULL;
+	char*       	        loc_name        = nullptr;
 	size_t        	 	loc_name_len    = 0;
 
-
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH(loc_name, loc_name_len)
 	ZEND_PARSE_PARAMETERS_END();
@@ -860,7 +861,7 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_keywords)
 
 	/* Get the keywords */
 	e = uloc_openKeywords( loc_name, &status );
-	if( e != NULL ) {
+	if( e != nullptr ) {
 		/*
 		ICU expects the buffer to be allocated  before calling the function
 		and so the buffer size has been explicitly specified
@@ -871,7 +872,7 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_keywords)
 		/* Traverse it, filling the return array. */
 		array_init( return_value );
 
-		while( ( kw_key = uenum_next( e, &kw_key_len, &status ) ) != NULL ){
+		while( ( kw_key = uenum_next( e, &kw_key_len, &status ) ) != nullptr ){
 			int32_t kw_value_len = 100;
 			zend_string *kw_value_str = zend_string_alloc(kw_value_len, 0);
 
@@ -885,7 +886,7 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_keywords)
 				kw_value_str = zend_string_truncate(kw_value_str, kw_value_len, 0);
 			}
 			if (U_FAILURE(status)) {
-				intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "Error encountered while getting the keyword value for the keyword");
+				intl_error_set( nullptr, U_ILLEGAL_ARGUMENT_ERROR, "Error encountered while getting the keyword value for the keyword");
 				if( kw_value_str){
 					zend_string_efree( kw_value_str );
 				}
@@ -896,7 +897,7 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_keywords)
 			add_assoc_str( return_value, (char *)kw_key, kw_value_str);
 		} /* end of while */
 
-	} /* end of if e!=NULL */
+	} /* end of if e!=nullptr */
 
 	uenum_close( e );
 }
@@ -921,7 +922,7 @@ static int append_key_value(smart_str* loc_name, HashTable* hash_arr, const char
 {
 	zval *ele_value;
 
-	if ((ele_value = zend_hash_str_find_deref(hash_arr , key_name, strlen(key_name))) != NULL ) {
+	if ((ele_value = zend_hash_str_find_deref(hash_arr , key_name, strlen(key_name))) != nullptr ) {
 		if(Z_TYPE_P(ele_value)!= IS_STRING ){
 			/* element value is not a string */
 			return FAILURE;
@@ -964,7 +965,7 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr,
 	int 	isFirstSubtag 	= 0;
 
 	/* Variant/ Extlang/Private etc. */
-	if ((ele_value = zend_hash_str_find_deref( hash_arr , key_name , strlen(key_name))) != NULL) {
+	if ((ele_value = zend_hash_str_find_deref( hash_arr , key_name , strlen(key_name))) != nullptr) {
 		if( Z_TYPE_P(ele_value) == IS_STRING ){
 			add_prefix( loc_name , key_name);
 
@@ -1008,7 +1009,7 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr,
 		isFirstSubtag = 0;
 		for( i=0 ; i< max_value; i++ ){
 			snprintf( cur_key_name , 30, "%s%d", key_name , i);
-			if ((ele_value = zend_hash_str_find_deref( hash_arr , cur_key_name , strlen(cur_key_name))) != NULL) {
+			if ((ele_value = zend_hash_str_find_deref( hash_arr , cur_key_name , strlen(cur_key_name))) != nullptr) {
 				if( Z_TYPE_P(ele_value)!= IS_STRING ){
 					/* variant is not a string */
 					return FAILURE;
@@ -1034,9 +1035,9 @@ static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr,
 */
 static int handleAppendResult( int result, smart_str* loc_name)
 {
-	intl_error_reset( NULL );
+	intl_error_reset( nullptr );
 	if( result == FAILURE) {
-		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+		intl_error_set( nullptr, U_ILLEGAL_ARGUMENT_ERROR,
 			 "parameter array element is not a string");
 		smart_str_free(loc_name);
 		return 0;
@@ -1052,13 +1053,12 @@ static int handleAppendResult( int result, smart_str* loc_name)
 * }}} */
 PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_compose)
 {
-	smart_str      	loc_name_s = {NULL, 0};
+	smart_str      	loc_name_s = {nullptr, 0};
 	smart_str *loc_name = &loc_name_s;
-	zval*			arr	= NULL;
-	HashTable*		hash_arr = NULL;
+	zval*			arr	= nullptr;
+	HashTable*		hash_arr = nullptr;
 	int 			result = 0;
 
-
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_ARRAY(arr)
 	ZEND_PARSE_PARAMETERS_END();
@@ -1125,15 +1125,15 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_compose)
 
 /*{{{
 * Parses the locale and returns private subtags  if existing
-* else returns NULL
+* else returns nullptr
 * e.g. for locale='en_US-x-prv1-prv2-prv3'
 * returns a pointer to the string 'prv1-prv2-prv3'
 */
 static zend_string* get_private_subtags(const char* loc_name)
 {
-	zend_string* result = NULL;
+	zend_string* result = nullptr;
 	size_t       len = 0;
-	const char*  mod_loc_name =NULL;
+	const char*  mod_loc_name =nullptr;
 
 	if( loc_name && (len = strlen(loc_name)) > 0 ){
 		zend_off_t singletonPos = 0;
@@ -1142,7 +1142,7 @@ static zend_string* get_private_subtags(const char* loc_name)
 			if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){
 				/* private subtag start found */
 				if( singletonPos + 2 ==  len){
-					/* loc_name ends with '-x-' ; return  NULL */
+					/* loc_name ends with '-x-' ; return  nullptr */
 				}
 				else{
 					/* result = mod_loc_name + singletonPos +2; */
@@ -1170,10 +1170,10 @@ static zend_string* get_private_subtags(const char* loc_name)
 /* {{{ code used by locale_parse */
 static int add_array_entry(const char* loc_name, zval* hash_arr, const char* key_name)
 {
-	zend_string*   key_value 	= NULL;
-	char*   cur_key_name	= NULL;
-	char*   token        	= NULL;
-	char*   last_ptr  	= NULL;
+	zend_string*   key_value 	= nullptr;
+	std::unique_ptr<char, char_deleter>   cur_key_name;
+	char*   token        	= nullptr;
+	char*   last_ptr  	= nullptr;
 
 	int	result		= 0;
 	int 	cur_result  	= 0;
@@ -1191,18 +1191,16 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, const char* key
 			int cnt = 0;
 			/* Tokenize on the "_" or "-"  */
 			token = php_strtok_r( key_value->val , DELIMITER ,&last_ptr);
-			if( cur_key_name ){
-				efree( cur_key_name);
-			}
 			/* Over-allocates a few bytes for the integer so we don't have to reallocate. */
 			size_t cur_key_name_size = (sizeof("-2147483648") - 1) + strlen(key_name) + 1;
-			cur_key_name = reinterpret_cast<char *>(emalloc(cur_key_name_size));
-			snprintf( cur_key_name, cur_key_name_size , "%s%d", key_name , cnt++);
-			add_assoc_string( hash_arr, cur_key_name , token);
+			cur_key_name.reset(reinterpret_cast<char *>(emalloc(cur_key_name_size)));
+			char *p_cur_key_name = cur_key_name.get();
+			snprintf( p_cur_key_name, cur_key_name_size , "%s%d", key_name , cnt++);
+			add_assoc_string( hash_arr, p_cur_key_name , token);
 			/* tokenize on the "_" or "-" and stop  at singleton if any */
-			while( (token = php_strtok_r(NULL , DELIMITER , &last_ptr)) && (strlen(token)>1) ){
-				snprintf( cur_key_name , cur_key_name_size, "%s%d", key_name , cnt++);
-				add_assoc_string( hash_arr, cur_key_name , token);
+			while( (token = php_strtok_r(nullptr , DELIMITER , &last_ptr)) && (strlen(token)>1) ){
+				snprintf( p_cur_key_name , cur_key_name_size, "%s%d", key_name , cnt++);
+				add_assoc_string( hash_arr, p_cur_key_name , token);
 			}
 /*
 			if( strcmp(key_name, LOC_PRIVATE_TAG) == 0 ){
@@ -1220,10 +1218,6 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, const char* key
 			zend_string_release_ex(key_value, 0);
 		}
 	}
-
-	if( cur_key_name ){
-		efree( cur_key_name);
-	}
 	/*if( key_name != LOC_PRIVATE_TAG && key_value){*/
 	return cur_result;
 }
@@ -1232,11 +1226,10 @@ 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 */
 PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_parse)
 {
-	char*          loc_name        = NULL;
+	char*          loc_name        = nullptr;
 	size_t         loc_name_len    = 0;
 	int         grOffset    	= 0;
 
-
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH(loc_name, loc_name_len)
 	ZEND_PARSE_PARAMETERS_END();
@@ -1267,14 +1260,13 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_parse)
 /* {{{ gets an array containing the list of variants, or null */
 PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_all_variants)
 {
-	char*  	                loc_name        = NULL;
+	char*  	                loc_name        = nullptr;
 	size_t    		loc_name_len    = 0;
 
 	int	result		= 0;
-	char*	token		= NULL;
-	zend_string*	variant		= NULL;
-	char*	saved_ptr	= NULL;
-
+	char*	token		= nullptr;
+	zend_string*	variant		= nullptr;
+	char*	saved_ptr	= nullptr;
 
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_PATH(loc_name, loc_name_len)
@@ -1301,7 +1293,7 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_all_variants)
 			token = php_strtok_r( variant->val , DELIMITER , &saved_ptr);
 			add_next_index_stringl( return_value, token , strlen(token));
 			/* tokenize on the "_" or "-" and stop  at singleton if any	*/
-			while( (token = php_strtok_r(NULL , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){
+			while( (token = php_strtok_r(nullptr , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){
 				add_next_index_stringl( return_value, token , strlen(token));
 			}
 		}
@@ -1317,8 +1309,8 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_get_all_variants)
 /* {{{ Converts to lower case and also replaces all hyphens with the underscore */
 static int strToMatch(const char* str ,char *retstr)
 {
-	char* 	anchor 	= NULL;
-	const char* 	anchor1 = NULL;
+	char* 	anchor 	= nullptr;
+	const char* 	anchor1 = nullptr;
 	int 	result 	= 0;
 
 	if( (!str) || str[0] == '\0'){
@@ -1350,25 +1342,24 @@ static int strToMatch(const char* str ,char *retstr)
 /* {{{ Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm */
 PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_filter_matches)
 {
-	char*       	lang_tag        = NULL;
+	char*       	lang_tag        = nullptr;
 	size_t         	lang_tag_len    = 0;
-	char*           loc_range       = NULL;
+	char*           loc_range       = nullptr;
 	size_t         	loc_range_len   = 0;
 
 	int		result		= 0;
 	char*		token		= 0;
-	char*		chrcheck	= NULL;
+	char*		chrcheck	= nullptr;
 
-	zend_string*   	can_lang_tag    = NULL;
-	zend_string*   	can_loc_range   = NULL;
+	zend_string*   	can_lang_tag    = nullptr;
+	zend_string*   	can_loc_range   = nullptr;
 
-	char*       	cur_lang_tag    = NULL;
-	char*       	cur_loc_range   = NULL;
+	std::unique_ptr<char, char_deleter> cur_lang_tag;
+	std::unique_ptr<char, char_deleter> cur_loc_range;
 
 	bool 	boolCanonical 	= 0;
 	UErrorCode	status		= U_ZERO_ERROR;
 
-
 	ZEND_PARSE_PARAMETERS_START(2, 3)
 		Z_PARAM_PATH(lang_tag, lang_tag_len)
 		Z_PARAM_PATH(loc_range,  loc_range_len)
@@ -1392,7 +1383,7 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_filter_matches)
 		/* canonicalize loc_range */
 		can_loc_range=get_icu_value_internal( loc_range , LOC_CANONICALIZE_TAG , &result , 0);
 		if( result <=0) {
-			intl_error_set(NULL, status, "unable to canonicalize loc_range");
+			intl_error_set(nullptr, status, "unable to canonicalize loc_range");
 			RETURN_FALSE;
 		}
 
@@ -1400,103 +1391,77 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_filter_matches)
 		can_lang_tag = get_icu_value_internal( lang_tag , LOC_CANONICALIZE_TAG , &result ,  0);
 		if( result <=0) {
 			zend_string_release_ex( can_loc_range, false );
-			intl_error_set(NULL, status, "unable to canonicalize lang_tag");
+			intl_error_set(nullptr, status, "unable to canonicalize lang_tag");
 			RETURN_FALSE;
 		}
 
 		/* Convert to lower case for case-insensitive comparison */
-		cur_lang_tag = reinterpret_cast<char *>(ecalloc( 1, can_lang_tag->len + 1));
+		cur_lang_tag = std::unique_ptr<char, char_deleter>(reinterpret_cast<char *>(ecalloc( 1, can_lang_tag->len + 1)));
+		char *p_cur_lang_tag = cur_lang_tag.get();
 
 		/* Convert to lower case for case-insensitive comparison */
-		result = strToMatch( can_lang_tag->val , cur_lang_tag);
+		result = strToMatch( can_lang_tag->val , p_cur_lang_tag);
 		if( result == 0) {
-			efree( cur_lang_tag );
-			zend_string_release_ex( can_lang_tag, 0 );
+			zend_string_release_ex( can_lang_tag, false );
 			RETURN_FALSE;
 		}
 
-		cur_loc_range = reinterpret_cast<char *>(ecalloc( 1, can_loc_range->len + 1));
-		result = strToMatch( can_loc_range->val , cur_loc_range );
+		cur_loc_range = std::unique_ptr<char, char_deleter>(reinterpret_cast<char *>(ecalloc( 1, can_loc_range->len + 1)));
+		char *p_cur_loc_range = cur_loc_range.get();
+		result = strToMatch( can_loc_range->val , p_cur_loc_range );
 		if( result == 0) {
-			efree( cur_lang_tag );
-			zend_string_release_ex( can_lang_tag, 0 );
-			efree( cur_loc_range );
-			zend_string_release_ex( can_loc_range, 0 );
+			zend_string_release_ex( can_lang_tag, false );
+			zend_string_release_ex( can_loc_range, false );
 			RETURN_FALSE;
 		}
 
 		/* check if prefix */
-		token 	= strstr( cur_lang_tag , cur_loc_range );
+		token 	= strstr( p_cur_lang_tag , p_cur_loc_range );
 
-		if( token && (token==cur_lang_tag) ){
+		if( token && (token==p_cur_lang_tag) ){
 			/* check if the char. after match is SEPARATOR */
 			chrcheck = token + can_loc_range->len;
 			if( isIDSeparator(*chrcheck) || isKeywordSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){
-				efree( cur_lang_tag );
-				efree( cur_loc_range );
-				if( can_lang_tag){
-					zend_string_release_ex( can_lang_tag, 0 );
-				}
-				if( can_loc_range){
-					zend_string_release_ex( can_loc_range, 0 );
-				}
+				zend_string_release_ex( can_lang_tag, false );
+				zend_string_release_ex( can_loc_range, false );
 				RETURN_TRUE;
 			}
 		}
 
 		/* No prefix as loc_range */
-		if( cur_lang_tag){
-			efree( cur_lang_tag );
-		}
-		if( cur_loc_range){
-			efree( cur_loc_range );
-		}
-		if( can_lang_tag){
-			zend_string_release_ex( can_lang_tag, 0 );
-		}
-		if( can_loc_range){
-			zend_string_release_ex( can_loc_range, 0 );
-		}
+		zend_string_release_ex( can_lang_tag, false );
+		zend_string_release_ex( can_loc_range, false );
 		RETURN_FALSE;
 
 	} /* end of if isCanonical */
 	else{
 		/* Convert to lower case for case-insensitive comparison */
-		cur_lang_tag = reinterpret_cast<char *>(ecalloc(1, lang_tag_len + 1));
+		cur_lang_tag = std::unique_ptr<char, char_deleter>(reinterpret_cast<char *>(ecalloc(1, lang_tag_len + 1)));
+		char *p_cur_lang_tag = cur_lang_tag.get();
 
-		result = strToMatch( lang_tag , cur_lang_tag);
+		result = strToMatch( lang_tag , p_cur_lang_tag);
 		if( result == 0) {
-			efree( cur_lang_tag );
 			RETURN_FALSE;
 		}
-		cur_loc_range = reinterpret_cast<char *>(ecalloc(1, loc_range_len + 1));
-		result = strToMatch( loc_range , cur_loc_range );
+		cur_loc_range = std::unique_ptr<char, char_deleter>(reinterpret_cast<char *>(ecalloc(1, loc_range_len + 1)));
+		char *p_cur_loc_range = cur_loc_range.get();
+		result = strToMatch( loc_range , p_cur_loc_range );
 		if( result == 0) {
-			efree( cur_lang_tag );
-			efree( cur_loc_range );
 			RETURN_FALSE;
 		}
 
 		/* check if prefix */
-		token 	= strstr( cur_lang_tag , cur_loc_range );
+		token 	= strstr( p_cur_lang_tag , p_cur_loc_range );
 
-		if( token && (token==cur_lang_tag) ){
+		if( token && (token==p_cur_lang_tag) ){
 			/* check if the char. after match is SEPARATOR */
 			chrcheck = token + loc_range_len;
 			if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){
-				efree( cur_lang_tag );
-				efree( cur_loc_range );
 				RETURN_TRUE;
 			}
 		}
 
 		/* No prefix as loc_range */
-		if( cur_lang_tag){
-			efree( cur_lang_tag );
-		}
-		if( cur_loc_range){
-			efree( cur_loc_range );
-		}
 		RETURN_FALSE;
 
 	}
@@ -1525,14 +1490,14 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 	int	cur_arr_len = 0;
 	int result = 0;
 
-	zend_string* lang_tag = NULL;
-	zval* ele_value = NULL;
+	zend_string* lang_tag = nullptr;
+	zval* ele_value = nullptr;
 
-	char* cur_loc_range	= NULL;
-	zend_string* can_loc_range	= NULL;
+	char* cur_loc_range	= nullptr;
+	zend_string* can_loc_range	= nullptr;
 	zend_off_t saved_pos = 0;
 
-	zend_string* return_value = NULL;
+	zend_string* return_value = nullptr;
 
 	char **cur_arr = reinterpret_cast<char **>(ecalloc(zend_hash_num_elements(hash_arr)*2, sizeof(char *)));
 	ZEND_HASH_FOREACH_VAL(hash_arr, ele_value) {
@@ -1541,19 +1506,19 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 		if(Z_TYPE_P(ele_value)!= IS_STRING) {
 			/* element value is not a string */
 			zend_argument_type_error(2, "must only contain string values");
-			LOOKUP_CLEAN_RETURN(NULL);
+			LOOKUP_CLEAN_RETURN(nullptr);
 		}
 		if (zend_str_has_nul_byte(Z_STR_P(ele_value))) {
 			zend_argument_value_error(2, "must not contain any null bytes");
-			LOOKUP_CLEAN_RETURN(NULL);
+			LOOKUP_CLEAN_RETURN(nullptr);
 		}
 		i = cur_arr_len*2;
 		cur_arr[i] = estrndup(Z_STRVAL_P(ele_value), Z_STRLEN_P(ele_value));
 		cur_arr_len++;
 		result = strToMatch(Z_STRVAL_P(ele_value), cur_arr[i]);
 		if(result == 0) {
-			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
-			LOOKUP_CLEAN_RETURN(NULL);
+			intl_error_set(nullptr, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
+			LOOKUP_CLEAN_RETURN(nullptr);
 		}
 		cur_arr[i+1] = Z_STRVAL_P(ele_value);
 	} ZEND_HASH_FOREACH_END(); /* end of for */
@@ -1562,19 +1527,19 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 	if(canonicalize) {
 		for(i=0; i<cur_arr_len; i++) {
 			lang_tag = get_icu_value_internal(cur_arr[i*2], LOC_CANONICALIZE_TAG, &result, 0);
-			if(result != 1 || lang_tag == NULL || !lang_tag->val[0]) {
+			if(result != 1 || lang_tag == nullptr || !lang_tag->val[0]) {
 				if(lang_tag) {
 					zend_string_release_ex(lang_tag, 0);
 				}
-				intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
-				LOOKUP_CLEAN_RETURN(NULL);
+				intl_error_set(nullptr, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
+				LOOKUP_CLEAN_RETURN(nullptr);
 			}
 			cur_arr[i*2] = reinterpret_cast<char *>(erealloc(cur_arr[i*2], lang_tag->len+1));
 			result = strToMatch(lang_tag->val, cur_arr[i*2]);
 			zend_string_release_ex(lang_tag, 0);
 			if(result == 0) {
-				intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
-				LOOKUP_CLEAN_RETURN(NULL);
+				intl_error_set(nullptr, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
+				LOOKUP_CLEAN_RETURN(nullptr);
 			}
 		}
 
@@ -1583,13 +1548,13 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 	if(canonicalize) {
 		/* Canonicalize the loc_range */
 		can_loc_range = get_icu_value_internal(loc_range, LOC_CANONICALIZE_TAG, &result , 0);
-		if( result != 1 || can_loc_range == NULL || !can_loc_range->val[0]) {
+		if( result != 1 || can_loc_range == nullptr || !can_loc_range->val[0]) {
 			/* Error */
-			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize loc_range");
+			intl_error_set(nullptr, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize loc_range");
 			if(can_loc_range) {
 				zend_string_release_ex(can_loc_range, 0);
 			}
-			LOOKUP_CLEAN_RETURN(NULL);
+			LOOKUP_CLEAN_RETURN(nullptr);
 		} else {
 			loc_range = can_loc_range->val;
 		}
@@ -1603,15 +1568,15 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 	}
 	if(result == 0) {
 		efree(cur_loc_range);
-		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
-		LOOKUP_CLEAN_RETURN(NULL);
+		intl_error_set(nullptr, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
+		LOOKUP_CLEAN_RETURN(nullptr);
 	}
 
 	/* Lookup for the lang_tag match */
 	saved_pos = strlen(cur_loc_range);
 	while(saved_pos > 0) {
 		for(i=0; i< cur_arr_len; i++){
-			if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {
+			if(cur_arr[i*2] != nullptr && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {
 				/* Match found */
 				char *str = canonicalize ? cur_arr[i*2] : cur_arr[i*2+1];
 				return_value = zend_string_init(str, strlen(str), 0);
@@ -1624,7 +1589,7 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 
 	/* Match not found */
 	efree(cur_loc_range);
-	LOOKUP_CLEAN_RETURN(NULL);
+	LOOKUP_CLEAN_RETURN(nullptr);
 }
 /* }}} */
 
@@ -1637,15 +1602,14 @@ static zend_string* lookup_loc_range(const char* loc_range, HashTable* hash_arr,
 */
 PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_lookup)
 {
-	zend_string*   	fallback_loc_str	= NULL;
-	char*    	loc_range      		= NULL;
+	zend_string*   	fallback_loc_str	= nullptr;
+	char*    	loc_range      		= nullptr;
 	size_t        	loc_range_len  		= 0;
 
-	zval*		arr				= NULL;
-	HashTable*	hash_arr		= NULL;
+	zval*		arr				= nullptr;
+	HashTable*	hash_arr		= nullptr;
 	bool	boolCanonical	= 0;
-	zend_string* 	result_str	= NULL;
-
+	zend_string* 	result_str	= nullptr;
 
 	ZEND_PARSE_PARAMETERS_START(2, 4)
 		Z_PARAM_ARRAY(arr)
@@ -1677,13 +1641,13 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_lookup)
 	if (EG(exception)) {
 		RETURN_THROWS();
 	}
-	if (U_FAILURE(intl_error_get_code(NULL))) {
+	if (U_FAILURE(intl_error_get_code(nullptr))) {
 		if (result_str) {
 			zend_string_release_ex(result_str, 0);
 		}
 		RETURN_NULL();
 	}
-	if(result_str == NULL || ZSTR_VAL(result_str)[0] == '\0') {
+	if(result_str == nullptr || ZSTR_VAL(result_str)[0] == '\0') {
 		if( fallback_loc_str ) {
 			result_str = zend_string_copy(fallback_loc_str);
 		} else {
@@ -1699,7 +1663,7 @@ PHP_INTL_FUNCTION_WITH_ERROR_RESET(locale_lookup)
 U_CFUNC PHP_FUNCTION(locale_accept_from_http)
 {
 	UEnumeration *available;
-	char *http_accept = NULL;
+	char *http_accept = nullptr;
 	size_t http_accept_len;
 	UErrorCode status = U_ZERO_ERROR;
 	int len;
@@ -1718,17 +1682,17 @@ U_CFUNC PHP_FUNCTION(locale_accept_from_http)
 			end = strchr(start, ',');
 			len = end ? end-start : http_accept_len-(start-http_accept);
 			if (UNEXPECTED(len > ULOC_FULLNAME_CAPACITY)) {
-				intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+				intl_error_set( nullptr, U_ILLEGAL_ARGUMENT_ERROR,
 						"locale string too long");
 				RETURN_FALSE;
 			}
 			if(end) {
 				start = end+1;
 			}
-		} while(end != NULL);
+		} while(end != nullptr);
 	}
 
-	available = ures_openAvailableLocales(NULL, &status);
+	available = ures_openAvailableLocales(nullptr, &status);
 	INTL_CHECK_STATUS(status, "failed to retrieve locale list");
 	len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN,
 						&outResult, http_accept, available, &status);