Commit 82d91d49d83 for php.net
commit 82d91d49d839cf611f578df7d6ff013d10926cd8
Author: Weilin Du <weilindu@php.net>
Date: Wed Sep 23 12:55:31 2026 +0800
ext/standard: Optimize result-row construction in array_map() with a null callback (#23809)
In this case we just init each value once.
diff --git a/ext/standard/array.c b/ext/standard/array.c
index f475eeebf05..4c3704c8510 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -7125,114 +7125,127 @@ PHP_FUNCTION(array_map)
}
}
- array_init_size(return_value, maxlen);
-
- if (!ZEND_FCI_INITIALIZED(fci)) {
- uint32_t *array_pos = ecalloc(n_arrays, sizeof(HashPosition));
- zval zv;
-
- /* We iterate through all the arrays at once. */
- for (k = 0; k < maxlen; k++) {
+ if (!maxlen) {
+ RETURN_EMPTY_ARRAY();
+ }
- /* If no callback, the result will be an array, consisting of current
- * entries from all arrays. */
- array_init_size(&result, n_arrays);
+ array_init_size(return_value, maxlen);
+ zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
- for (i = 0; i < n_arrays; i++) {
- /* If this array still has elements, add the current one to the
- * parameter list, otherwise use null value. */
- uint32_t pos = array_pos[i];
- if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
- while (1) {
- if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
- ZVAL_NULL(&zv);
- break;
- } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
- ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arPacked[pos]);
- array_pos[i] = pos + 1;
- break;
- }
- pos++;
- }
- } else {
- while (1) {
- if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
- ZVAL_NULL(&zv);
- break;
- } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
- ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val);
- array_pos[i] = pos + 1;
- break;
+ ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
+ if (!ZEND_FCI_INITIALIZED(fci)) {
+ uint32_t *array_pos = ecalloc(n_arrays, sizeof(HashPosition));
+ zval zv;
+
+ /* We iterate through all the arrays at once. */
+ for (k = 0; k < maxlen; k++) {
+
+ /* If no callback, the result will be an array, consisting of current
+ * entries from all arrays. */
+ array_init_size(&result, n_arrays);
+
+ zend_hash_real_init_packed(Z_ARRVAL(result));
+ ZEND_HASH_FILL_PACKED(Z_ARRVAL(result)) {
+ for (i = 0; i < n_arrays; i++) {
+ /* If this array still has elements, add the current one to the
+ * parameter list, otherwise use null value. */
+ uint32_t pos = array_pos[i];
+ if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
+ while (1) {
+ if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
+ ZEND_HASH_FILL_SET_NULL();
+ break;
+ } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
+ ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arPacked[pos]);
+ ZEND_HASH_FILL_SET(&zv);
+ array_pos[i] = pos + 1;
+ break;
+ }
+ pos++;
+ }
+ } else {
+ while (1) {
+ if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
+ ZEND_HASH_FILL_SET_NULL();
+ break;
+ } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
+ ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val);
+ ZEND_HASH_FILL_SET(&zv);
+ array_pos[i] = pos + 1;
+ break;
+ }
+ pos++;
+ }
}
- pos++;
+ ZEND_HASH_FILL_NEXT();
}
- }
- zend_hash_next_index_insert_new(Z_ARRVAL(result), &zv);
- }
+ } ZEND_HASH_FILL_END();
- zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
- }
-
- efree(array_pos);
- } else {
- zval *params = (zval *)safe_emalloc(n_arrays, sizeof(zval), 0);
-
- /* Remember next starting point in the array, initialize those as zeros. */
- for (i = 0; i < n_arrays; i++) {
- Z_EXTRA(params[i]) = 0;
- }
+ ZEND_HASH_FILL_ADD(&result);
+ }
- fci.retval = &result;
- fci.param_count = n_arrays;
- fci.params = params;
+ efree(array_pos);
+ } else {
+ zval *params = (zval *)safe_emalloc(n_arrays, sizeof(zval), 0);
- /* We iterate through all the arrays at once. */
- for (k = 0; k < maxlen; k++) {
+ /* Remember next starting point in the array, initialize those as zeros. */
for (i = 0; i < n_arrays; i++) {
- /* If this array still has elements, add the current one to the
- * parameter list, otherwise use null value. */
- uint32_t pos = Z_EXTRA(params[i]);
- if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
- while (1) {
- if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
- ZVAL_NULL(¶ms[i]);
- break;
- } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
- ZVAL_COPY_VALUE(¶ms[i], &Z_ARRVAL(arrays[i])->arPacked[pos]);
- Z_EXTRA(params[i]) = pos + 1;
- break;
+ Z_EXTRA(params[i]) = 0;
+ }
+
+ fci.retval = &result;
+ fci.param_count = n_arrays;
+ fci.params = params;
+
+ /* We iterate through all the arrays at once. */
+ for (k = 0; k < maxlen; k++) {
+ for (i = 0; i < n_arrays; i++) {
+ /* If this array still has elements, add the current one to the
+ * parameter list, otherwise use null value. */
+ uint32_t pos = Z_EXTRA(params[i]);
+ if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
+ while (1) {
+ if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
+ ZVAL_NULL(¶ms[i]);
+ break;
+ } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
+ ZVAL_COPY_VALUE(¶ms[i], &Z_ARRVAL(arrays[i])->arPacked[pos]);
+ Z_EXTRA(params[i]) = pos + 1;
+ break;
+ }
+ pos++;
}
- pos++;
- }
- } else {
- while (1) {
- if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
- ZVAL_NULL(¶ms[i]);
- break;
- } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
- ZVAL_COPY_VALUE(¶ms[i], &Z_ARRVAL(arrays[i])->arData[pos].val);
- Z_EXTRA(params[i]) = pos + 1;
- break;
+ } else {
+ while (1) {
+ if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
+ ZVAL_NULL(¶ms[i]);
+ break;
+ } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
+ ZVAL_COPY_VALUE(¶ms[i], &Z_ARRVAL(arrays[i])->arData[pos].val);
+ Z_EXTRA(params[i]) = pos + 1;
+ break;
+ }
+ pos++;
}
- pos++;
}
}
- }
- zend_result ret = zend_call_function(&fci, &fci_cache);
- ZEND_ASSERT(ret == SUCCESS);
- ZEND_IGNORE_VALUE(ret);
+ zend_result ret = zend_call_function(&fci, &fci_cache);
+ ZEND_ASSERT(ret == SUCCESS);
+ ZEND_IGNORE_VALUE(ret);
- if (Z_TYPE(result) == IS_UNDEF) {
- efree(params);
- RETURN_THROWS();
+ if (Z_TYPE(result) == IS_UNDEF) {
+ ZEND_HASH_FILL_FINISH();
+ efree(params);
+ RETURN_THROWS();
+ }
+
+ ZEND_HASH_FILL_ADD(&result);
}
- zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
+ efree(params);
}
-
- efree(params);
- }
+ } ZEND_HASH_FILL_END();
}
}
/* }}} */