mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
json: Improve performance of php_json_encode_array() (#20092)
Instead of using a boolean flag to check for each element whether or not it is
the first, we just unconditionally append a comma after each element and then
remove the last comma at the end.
For:
<?php
$len = 0;
for ($i = 0; $i < 3_000_000; $i++) {
$len += strlen(json_encode(array_fill(0, 20, [])));
}
var_dump($len);
This is ~1.06 faster for a gcc 13.3 release build on a Intel(R) Core(TM)
i7-1365U.
Benchmark 1: /tmp/bench/before /tmp/bench/test6.php
Time (mean ± σ): 819.6 ms ± 2.8 ms [User: 816.4 ms, System: 2.4 ms]
Range (min … max): 816.9 ms … 825.0 ms 10 runs
Benchmark 2: /tmp/bench/after /tmp/bench/test6.php
Time (mean ± σ): 770.8 ms ± 5.8 ms [User: 766.6 ms, System: 2.9 ms]
Range (min … max): 765.3 ms … 785.8 ms 10 runs
Summary
/tmp/bench/after /tmp/bench/test6.php ran
1.06 ± 0.01 times faster than /tmp/bench/before /tmp/bench/test6.php
This commit is contained in:
@@ -84,3 +84,6 @@ PHP 8.6 UPGRADE NOTES
|
||||
========================================
|
||||
14. Performance Improvements
|
||||
========================================
|
||||
|
||||
- JSON:
|
||||
. Improve performance of encoding arrays and objects.
|
||||
|
||||
@@ -109,7 +109,6 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options)
|
||||
static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, php_json_encoder *encoder) /* {{{ */
|
||||
{
|
||||
bool encode_as_object = options & PHP_JSON_FORCE_OBJECT;
|
||||
bool need_comma = false;
|
||||
HashTable *myht, *prop_ht;
|
||||
zend_refcounted *recursion_rc;
|
||||
|
||||
@@ -161,12 +160,6 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (need_comma) {
|
||||
smart_str_appendc(buf, ',');
|
||||
} else {
|
||||
need_comma = true;
|
||||
}
|
||||
|
||||
php_json_pretty_print_char(buf, options, '\n');
|
||||
php_json_pretty_print_indent(buf, options, encoder);
|
||||
|
||||
@@ -186,6 +179,14 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(obj);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
smart_str_appendc(buf, ',');
|
||||
}
|
||||
|
||||
bool empty = ZSTR_VAL(buf->s)[ZSTR_LEN(buf->s) - 1] != ',';
|
||||
if (!empty) {
|
||||
/* Drop the trailing comma. */
|
||||
ZSTR_LEN(buf->s)--;
|
||||
}
|
||||
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(obj);
|
||||
@@ -197,7 +198,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
}
|
||||
--encoder->depth;
|
||||
|
||||
if (need_comma) {
|
||||
if (!empty) {
|
||||
php_json_pretty_print_char(buf, options, '\n');
|
||||
php_json_pretty_print_indent(buf, options, encoder);
|
||||
}
|
||||
@@ -235,6 +236,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
|
||||
uint32_t i = myht ? zend_hash_num_elements(myht) : 0;
|
||||
|
||||
bool empty = true;
|
||||
if (i > 0) {
|
||||
zend_string *key;
|
||||
zval *data;
|
||||
@@ -247,12 +249,6 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
if (!encode_as_object) {
|
||||
ZEND_ASSERT(Z_TYPE_P(data) != IS_PTR);
|
||||
|
||||
if (need_comma) {
|
||||
smart_str_appendc(buf, ',');
|
||||
} else {
|
||||
need_comma = true;
|
||||
}
|
||||
|
||||
php_json_pretty_print_char(buf, options, '\n');
|
||||
php_json_pretty_print_indent(buf, options, encoder);
|
||||
} else {
|
||||
@@ -276,11 +272,6 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
}
|
||||
}
|
||||
|
||||
if (need_comma) {
|
||||
smart_str_appendc(buf, ',');
|
||||
} else {
|
||||
need_comma = true;
|
||||
}
|
||||
|
||||
php_json_pretty_print_char(buf, options, '\n');
|
||||
php_json_pretty_print_indent(buf, options, encoder);
|
||||
@@ -293,12 +284,6 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
smart_str_appendl(buf, "\"\"", 2);
|
||||
}
|
||||
} else {
|
||||
if (need_comma) {
|
||||
smart_str_appendc(buf, ',');
|
||||
} else {
|
||||
need_comma = true;
|
||||
}
|
||||
|
||||
php_json_pretty_print_char(buf, options, '\n');
|
||||
php_json_pretty_print_indent(buf, options, encoder);
|
||||
|
||||
@@ -319,7 +304,15 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
return FAILURE;
|
||||
}
|
||||
zval_ptr_dtor(&tmp);
|
||||
|
||||
smart_str_appendc(buf, ',');
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
empty = ZSTR_VAL(buf->s)[ZSTR_LEN(buf->s) - 1] != ',';
|
||||
if (!empty) {
|
||||
/* Drop the trailing comma. */
|
||||
ZSTR_LEN(buf->s)--;
|
||||
}
|
||||
}
|
||||
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(recursion_rc);
|
||||
@@ -334,7 +327,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
|
||||
--encoder->depth;
|
||||
|
||||
/* Only keep closing bracket on same line for empty arrays/objects */
|
||||
if (need_comma) {
|
||||
if (!empty) {
|
||||
php_json_pretty_print_char(buf, options, '\n');
|
||||
php_json_pretty_print_indent(buf, options, encoder);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user