Skip to content

Commit 447f07c

Browse files
TysonAndrenikic
authored andcommitted
Optimize creation of empty arrays in json_decode
Use the shared empty array from ZVAL_EMPTY_ARRAY For code that created an 10 arrays of 100000 empty arrays (has the same result with `$assoc=true` and `{}`) - This is the worst-case comparison, but I'd expect 0-length arrays to be fairly common in regular data for json_decode - The parser implementation was using function pointers so that third party extension developers could reuse the json parser for their own data structures, etc. (I think). This PR is meant to let those third party extensions continue working without changes. Before this patch: In 0.126 seconds: added 97.99 MiB After this patch: In 0.096 seconds: added 41.99 MiB ```php <?php $json = '[' . str_repeat('[],', 100000) . "null]"; $start_memory = memory_get_usage(); $start_time = microtime(true); $result = []; for ($i = 0; $i < 10; $i++) { $result[] = json_decode($json); } $end_memory = memory_get_usage(); $end_time = microtime(true); // Before this patch: In 0.126 seconds: added 97.99 MiB // After this patch: In 0.096 seconds: added 41.99 MiB printf("In %.3f seconds: added %.2f MiB\n", $end_time - $start_time, ($end_memory - $start_memory)/1000000); // For objects $json = '[' . str_repeat('{},', 100000) . "null]"; $start_memory = memory_get_usage(); $start_time = microtime(true); for ($i = 0; $i < 10; $i++) { $result[] = json_decode($json, true); } $end_memory = memory_get_usage(); $end_time = microtime(true); // Before this patch: In 0.126 seconds: added 97.99 MiB // After this patch: In 0.096 seconds: added 41.99 MiB printf("In %.3f seconds: added %.2f MiB (objects decoded as arrays) \n", $end_time - $start_time, ($end_memory - $start_memory)/1000000); ``` Closes GH-4861.
1 parent 7816275 commit 447f07c

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

ext/json/json_parser.y

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ int json_yydebug = 1;
7676
%code {
7777
static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
7878
static void php_json_yyerror(php_json_parser *parser, char const *msg);
79+
static int php_json_parser_array_create(php_json_parser *parser, zval *array);
80+
static int php_json_parser_object_create(php_json_parser *parser, zval *array);
7981

8082
}
8183

@@ -120,7 +122,11 @@ object_end:
120122
members:
121123
/* empty */
122124
{
123-
parser->methods.object_create(parser, &$$);
125+
if ((parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) && parser->methods.object_create == php_json_parser_object_create) {
126+
ZVAL_EMPTY_ARRAY(&$$);
127+
} else {
128+
parser->methods.object_create(parser, &$$);
129+
}
124130
}
125131
| member
126132
;
@@ -180,7 +186,11 @@ array_end:
180186
elements:
181187
/* empty */
182188
{
183-
parser->methods.array_create(parser, &$$);
189+
if (parser->methods.array_create == php_json_parser_array_create) {
190+
ZVAL_EMPTY_ARRAY(&$$);
191+
} else {
192+
parser->methods.array_create(parser, &$$);
193+
}
184194
}
185195
| element
186196
;

0 commit comments

Comments
 (0)