[php-src] Issue #9429: array_key_exists on $GLOBALS takes linear time in PHP 8.1.0+
| From: | leejt | Date: | Fri, 26 Aug 2022 09:18:25 +0000 |
| Subject: | [php-src] Issue #9429: array_key_exists on $GLOBALS takes linear time in PHP 8.1.0+ | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-242313@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/9429
Author: leejt
### Description
Compare the following in PHP 8.0.22 vs 8.1.9 (https://3v4l.org/4kBiT)
```php
<?php
$a = [];
for ($i = 0; $i < 100000; $i++) {
$GLOBALS["a$i"] = rand(0, 1000000);
$a["a$i"] = rand(0, 1000000);
}
$start = microtime(true);
for ($runs = 1000; $runs > 0; $runs--) {
array_key_exists('a1111111', $GLOBALS);
}
$end = microtime(true);
printf("[GLOBALS]array_key_exists() took %.5f seconds\n", $end - $start);
```
It takes 0.00002 seconds in 8.0.22, and 1.9 seconds in 8.1.9.
Further testing makes it clear that the speed of array_key_exists on $GLOBALS increases linearly
with the size of $GLOBALS.
This regression doesn't affect array_key_exists on non-$GLOBALS arrays, and doesn't affect
the speed of
isset($GLOBALS[$foo].
The commit that introduced the slowdown was https://github.com/php/php-src/commit/3c68f38fdaec7a6f81f986a639bdd29716cf8f22,
which restricted usage of $GLOBALS in various ways. I'm not sure if this particular side effect
was known or intended.
array_key_exists is used somewhat often on $GLOBALS in MediaWiki, most prominently
[here](https://github.com/wikimedia/mediawiki/blob/master/includes/config/GlobalVarConfig.php#L91).
The behavior can be mostly replaced by calling isset($GLOBALS[$foo], which remains
fast, although that has different semantics when the value is null. I'm not aware of a better
way to get the full behavior of array_key_exists($foo, $GLOBALS) in constant-time in
8.1+.
### PHP Version
PHP 8.1.9
### Operating System
Ubuntu 20.04