

Der @-Operator ist nicht nur bei Anfängern der PHP-Programmierung sehr beliebt. Ob Variablen definiert sind oder Dateien existieren muss nicht extra via isset() bzw. file_exists() abgefragt werden. Ein einfaches @-Zeichen vor dem Variablennamen oder der include()-Funktion und schon sind scheinbar alle Probleme gelöst.
Doch was so einfach klingt ist in Wirklichkeit eine weit verbreitete Unterschätzung dessen, wieviel der harmlose @-Operator tatsächlich kostet. Der von PHP betriebene Aufwand entspricht in etwa dem zweifachen Ausführen der ini_set()-Funktion.
Zur Veranschaulichung haben wir drei PHP-Scripte erstellt und sie einem Benchmark-Test unterzogen.
Code:<?
for ($i=0;$i<10000;$i++){
echo @$test;
}
?>
Erläuterung:
Eine nicht definierte Variable $test soll via echo ausgegeben werden. Damit keine Fehlermeldung Notice undefined variable test erscheint, verwenden wir den @-Operator. Um ein aussagekräftiges Ergebnis zu erhalten, wird die Ausgabe in einer Schleife mit 10.000 Durchläufen ausgeführt.
Code:<?
for ($i=0;$i<10000;$i++){
$alt=ini_set("error_reporting",0);
echo $test;
ini_set("error_reporting",$alt);
}
?>
Erläuterung:
Dieser Code ist wohl nicht nur für erfahrene PHP-Programmierer ein Albtraum. Davon abgesehen, dass die PHP-Funktion ini_set() nach Möglichkeit vermieden werden sollte, würde Sie jeder annährend auf Performance achtende Programmierer außerhalb der Schleife verwenden. Wir möchten mit diesem Code belegen, welch enormer Aufwand beim Interpretieren des @-Operators entsteht.
Code:<?
for ($i=0;$i<10000;$i++){
if (isset($test)){echo $test;}
}
?>
Erläuterung:
Die nicht definierte Variable $test würde via echo ausgegeben werden. Da jedoch die Überprüfung mit isset() false zurückgibt, erfolgt keine Ausgabe. Auch diese Zeile wird in einer Schleife 10.000mal aufgerufen.
| Requests per second (RPS) | Time per Request (TPR) | Vergleich | ||
| PHP-Script mit @-Operator | 28.47 [#/sec] (mean) | 35.125 [ms] (mean) | 33.3% | 24.8% |
| PHP-Script mit ini_set() | 21.41 [#/sec] (mean) | 46.703 [ms] (mean) | ||
| PHP-Script mit isset() | 199.38 [#/sec] (mean) | 5.016 [ms] (mean) | 831.2% | 89.3% |
Das Ergebnis des Benachmark-Tests bestätigt unsere Vermutung: Unser Script mit dem @-Operator benötigt nur rund 25% weniger Zeit als der PHP-Code mit zweifachem Aufruf der ini_set()-Funktion. Die „saubere” Variante mit der Überprüfung via isset() ist fast 9mal schneller als das PHP-Script mit ini_set() und über 7mal schneller als der Code mit Verwendung des @-Operators.
Es kann nur ein Fazit geben: Der @-Operator zur Unterdrückung von Fehlermeldungen ist bei der Programmierung mit PHP unbedingt zu vermeiden.
Nachdem wir nun erfahren haben, dass mit Vermeidung des @-Operators bei Variablen in nicht unerheblichem Umfang Zeit und Ressourcen gespart werden können, interessiert uns die mögliche Ersparnis beim includieren nicht vorhandener Dateien. Wir erstellen folgende beiden PHP-Scripte:
Code:<?
for ($i=0;$i<10000;$i++){
@include("./beispiel.php");
}
?>
Erläuterung:
In einer for()-Schleife wird 10.000 mal versucht, eine nicht vorhandene beispiel.php-Datei zu includieren. Um die Fehlermeldung Warning: include(./beispiel.php) [function.include]: failed to open stream: No such file or directory zu unterdrücken, verwenden wir den @-Operator.
Code:<?
for ($i=0;$i<10000;$i++){
if (file_exists("./beispiel.php")){include("./beispiel.php");}
}
?>
Erläuterung:
Vor Aufruf der include()-Funktion wird geprüft, ob die zu includierende Datei existiert. Da file_exists() in unserem Beispiel false zurückgibt, wird das include()-Statement nicht aufgerufen und kann entsprechend keine Fehlermeldung verursachen.
| Requests per second (RPS) | Time per Request (TPR) | Vergleich | ||
| PHP-Script mit @-Operator | 0.36 [#/sec] (mean) | 2799.563 [ms] (mean) | ||
| include() mit file_exists() | 0.50 [#/sec] (mean) | 1988.438 [ms] (mean) | 38.9% | 29.0% |
Die Existenz einer zu includierenden Datei mit file_exists() vor Aufruf der include()-Funktion zu prüfen war in unserem Benchmark-Test 1,4mal schneller als der include()-Funktion den @-Operator voranzustellen.
Da auch die file_exists() beim Interpretieren für PHP einen gewissen Aufwand bedeutet, ist der Unterschied nicht ganz so gravierend wie bei der simplen Ausgabe einer Variable in unserem ersten Benchmark. Aber auch der 29%ige Zeitgewinn verdeutlicht, dass der @-Operator unbedingt umgangen werden sollte.
Anmerkung:
Die Tests wurden mit dem Apache HTTP server benchmarking tool ab auf einem im Februar 2012 nicht mehr dem Stand der Technik entsprechenden Server durchgeführt. Die RPS und TPR der getesteten PHP-Scripte sollten auf einem im Produktiv-Einsatz befindlichen Webserver deutlich besser sein.