diff options
author | Tyson Andre <tysonandre775@hotmail.com> | 2019-10-25 19:57:39 -0400 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-10-30 11:06:46 +0100 |
commit | 447f07cd28494caf6c9f08640bc6d355f93ed2f2 (patch) | |
tree | 37b6f70e7d5b3cf96f9d2a14cb71fac0eba013f9 /ext/json | |
parent | 78162752442e3f431243a2ad54177cad260aa7be (diff) | |
download | php-git-447f07cd28494caf6c9f08640bc6d355f93ed2f2.tar.gz |
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.
Diffstat (limited to 'ext/json')
-rw-r--r-- | ext/json/json_parser.y | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index ba7311c963..aec9b225b8 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -76,6 +76,8 @@ int json_yydebug = 1; %code { static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); static void php_json_yyerror(php_json_parser *parser, char const *msg); +static int php_json_parser_array_create(php_json_parser *parser, zval *array); +static int php_json_parser_object_create(php_json_parser *parser, zval *array); } @@ -120,7 +122,11 @@ object_end: members: /* empty */ { - parser->methods.object_create(parser, &$$); + if ((parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) && parser->methods.object_create == php_json_parser_object_create) { + ZVAL_EMPTY_ARRAY(&$$); + } else { + parser->methods.object_create(parser, &$$); + } } | member ; @@ -180,7 +186,11 @@ array_end: elements: /* empty */ { - parser->methods.array_create(parser, &$$); + if (parser->methods.array_create == php_json_parser_array_create) { + ZVAL_EMPTY_ARRAY(&$$); + } else { + parser->methods.array_create(parser, &$$); + } } | element ; |