php / php/php-src

array_key_exists on $GLOBALS takes linear time in PHP 8.1.0+

Offen
#9,429 3 Kommentare 6 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bug Category: Engine Status: Needs Triage
Vorherrschende Sprache
C
Sterne
40.4k
Forks
8.1k
Ø Merge
2 T. 13 Std.
Gemergte PRs (30 T.)
96

Beschreibung

Description

Compare the following in PHP 8.0.22 vs 8.1.9 (https://3v4l.org/91CFl)

<?php

for ($i = 0; $i < 100000; $i++) {
    $GLOBALS["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.

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Reproduziere den PHP 8.0.22/8.1.9-Benchmark aus dem Issue und untersuche anschließend den Commit 3c68f38fdaec7a6f81f986a639bdd29716cf8f22, der die Verwendung von $GLOBALS eingeschränkt hat. Die Arbeit ist abgeschlossen, wenn array_key_exists($foo, $GLOBALS) nicht mehr linear mit der Größe von $GLOBALS skaliert und dabei seine Semantik für Nullwerte beibehält; vergleiche das Ergebnis mit dem Verhalten von isset.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
c, php
Bereich
backend, performance
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.