Commit 82477067513 for php.net
commit 824770675130360543604e03b9f828a0e41c91ad
Author: Xuyang Zhang <119476662+kn1g78@users.noreply.github.com>
Date: Sat Jun 27 18:08:38 2026 +0800
ext/intl: Pre-size arrays created from ICU enumerations (#22483)
Use uenum_count() to pre-size arrays built from ICU enumerations.
This avoids unnecessary HashTable growth in transliterator_list_ids(),
resourcebundle_locales() and locale_get_keywords().
locale_get_keywords() also uses the keyword length reported by ICU when
inserting the associative entry, with a fallback to strlen() for unknown
lengths.
If counting fails, the previous behavior is preserved by falling back to an
unsized array initialization.
diff --git a/UPGRADING b/UPGRADING
index 15c1aad15db..0c5253267e3 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -500,6 +500,10 @@ PHP 8.6 UPGRADE NOTES
. Improved performance of indentation generation in json_encode()
when using PHP_JSON_PRETTY_PRINT.
+- Intl:
+ . Improved performance of transliterator_list_ids() and
+ resourcebundle_locales() by pre-allocating their returned arrays.
+
- Phar:
. Reduced temporary allocations when iterating Phar directories.
diff --git a/ext/intl/resourcebundle/resourcebundle_class.cpp b/ext/intl/resourcebundle/resourcebundle_class.cpp
index f796a6ffc8a..7e22e9e8c7d 100644
--- a/ext/intl/resourcebundle/resourcebundle_class.cpp
+++ b/ext/intl/resourcebundle/resourcebundle_class.cpp
@@ -339,6 +339,7 @@ U_CFUNC PHP_FUNCTION( resourcebundle_locales )
size_t bundlename_len = 0;
const char * entry;
int entry_len;
+ int32_t count;
UEnumeration *icuenum;
UErrorCode icuerror = U_ZERO_ERROR;
@@ -364,7 +365,13 @@ U_CFUNC PHP_FUNCTION( resourcebundle_locales )
uenum_reset( icuenum, &icuerror );
INTL_CHECK_STATUS(icuerror, "Cannot iterate locales list");
- array_init( return_value );
+ count = uenum_count( icuenum, &icuerror );
+ if (U_FAILURE(icuerror)) {
+ count = 0;
+ icuerror = U_ZERO_ERROR;
+ }
+
+ array_init_size( return_value, count );
while ((entry = uenum_next( icuenum, &entry_len, &icuerror ))) {
add_next_index_stringl( return_value, (char *) entry, entry_len);
}
diff --git a/ext/intl/transliterator/transliterator_methods.cpp b/ext/intl/transliterator/transliterator_methods.cpp
index 45dd00b42bc..8efcff95b31 100644
--- a/ext/intl/transliterator/transliterator_methods.cpp
+++ b/ext/intl/transliterator/transliterator_methods.cpp
@@ -21,6 +21,8 @@
#include <unicode/unistr.h>
#endif
+#include <unicode/uenum.h>
+
extern "C" {
#include "php_intl.h"
#include "intl_data.h"
@@ -226,6 +228,7 @@ U_CFUNC PHP_FUNCTION( transliterator_list_ids )
UEnumeration *en;
const UChar *elem;
int32_t elem_len;
+ int32_t count;
UErrorCode status = U_ZERO_ERROR;
intl_error_reset( nullptr );
@@ -236,7 +239,14 @@ U_CFUNC PHP_FUNCTION( transliterator_list_ids )
INTL_CHECK_STATUS( status,
"Failed to obtain registered transliterators" );
- array_init( return_value );
+ count = uenum_count( en, &status );
+ if( U_FAILURE( status ) )
+ {
+ count = 0;
+ status = U_ZERO_ERROR;
+ }
+
+ array_init_size( return_value, count );
while( (elem = uenum_unext( en, &elem_len, &status )) )
{
zend_string *el = intl_convert_utf16_to_utf8(elem, elem_len, &status );