Commit a4bb03a84b8 for php

commit a4bb03a84b8a1d81d896fb7a8bf3267cdafc5405
Author: Tim Düsterhus <tim@tideways-gmbh.com>
Date:   Sat Sep 26 09:44:28 2026 +0200

    standard: Take `HashTable*` instead of `zval*` in `php_explode()` (#23910)

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 4b5eed39a7b..a97aa97e528 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -29,6 +29,10 @@ PHP 8.7 INTERNALS UPGRADE NOTES
 3. Module changes
 ========================

+- Standard:
+  . php_explode() now takes a HashTable* instead of a zval* to store the
+    resulting parts. It already expected the zval* to be IS_ARRAY.
+
 ========================
 4. OpCode changes
 ========================
diff --git a/ext/standard/php_string.h b/ext/standard/php_string.h
index 412a4a4fa7a..7b8f8a8d3da 100644
--- a/ext/standard/php_string.h
+++ b/ext/standard/php_string.h
@@ -50,7 +50,7 @@ PHPAPI zend_string *php_trim(zend_string *str, const char *what, size_t what_len
 PHPAPI size_t php_strip_tags(char *rbuf, size_t len, const char *allow, size_t allow_len);
 PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, const char *allow, size_t allow_len, bool allow_tag_spaces);
 PHPAPI void php_implode(const zend_string *delim, HashTable *arr, zval *return_value);
-PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit);
+PHPAPI void php_explode(const zend_string *delim, zend_string *str, HashTable *parts, zend_long limit);

 PHPAPI size_t php_strspn(const char *s1, const char *s2, const char *s1_end, const char *s2_end);
 PHPAPI size_t php_strcspn(const char *s1, const char *s2, const char *s1_end, const char *s2_end);
diff --git a/ext/standard/string.c b/ext/standard/string.c
index bfe0c71795b..ddd3f31bf14 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -875,7 +875,7 @@ PHP_FUNCTION(wordwrap)
 /* }}} */

 /* {{{ php_explode */
-PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
+PHPAPI void php_explode(const zend_string *delim, zend_string *str, HashTable *parts, zend_long limit)
 {
 	const char *p1 = ZSTR_VAL(str);
 	const char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
@@ -884,10 +884,10 @@ PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return

 	if (p2 == NULL) {
 		ZVAL_STR_COPY(&tmp, str);
-		zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
+		zend_hash_next_index_insert_new(parts, &tmp);
 	} else {
-		zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
-		ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
+		zend_hash_real_init_packed(parts);
+		ZEND_HASH_FILL_PACKED(parts) {
 			do {
 				ZEND_HASH_FILL_GROW();
 				ZEND_HASH_FILL_SET_STR(zend_string_init_fast(p1, p2 - p1));
@@ -907,7 +907,7 @@ PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return
 /* }}} */

 /* {{{ php_explode_negative_limit */
-PHPAPI void php_explode_negative_limit(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
+static void php_explode_negative_limit(const zend_string *delim, zend_string *str, HashTable *parts, zend_long limit)
 {
 #define EXPLODE_ALLOC_STEP 64
 	const char *p1 = ZSTR_VAL(str);
@@ -939,7 +939,7 @@ PHPAPI void php_explode_negative_limit(const zend_string *delim, zend_string *st
 		/* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
 		for (i = 0; i < to_return; i++) { /* this checks also for to_return > 0 */
 			ZVAL_STRINGL_FAST(&tmp, positions[i], (positions[i+1] - ZSTR_LEN(delim)) - positions[i]);
-			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
+			zend_hash_next_index_insert_new(parts, &tmp);
 		}
 		efree((void *)positions);
 	}
@@ -977,9 +977,9 @@ PHP_FUNCTION(explode)
 	}

 	if (limit > 1) {
-		php_explode(delim, str, return_value, limit);
+		php_explode(delim, str, Z_ARRVAL_P(return_value), limit);
 	} else if (limit < 0) {
-		php_explode_negative_limit(delim, str, return_value, limit);
+		php_explode_negative_limit(delim, str, Z_ARRVAL_P(return_value), limit);
 	} else {
 		ZVAL_STR_COPY(&tmp, str);
 		zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);