

Lässt sich wirklich die Performance von PHP-Scripten verbessern, wenn vor dem Ersetzen mit str_replace() geprüft wird, ob der zu ersetzende Teilstring im Gesamtstring enthalten ist? Wir haben diesen weit verbreiteten Optimierungs-Tipp einem Benchmark unterzogen.
Code:<?
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=str_replace("f","g",$string);
}
?>
Erläuterung:
Innerhalb der ersten for()-Schleife wird ein String mit einer Länge von 2.000 Zeichen generiert. Mittels der zweiten for()-Schleife wird eine Ersetzung via str_replace() vorgenommen.
Code:<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=str_replace("m","g",$string);
}
?>
Erläuterung:
Im Unterschied zum ersten Beispiel-Script ist der zu ersetzende Teilstring im Gesamtstring nicht enthalten.
Code:<?
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($string,"f")!==false){
$test=str_replace("f","g",$string);
}
}
?>
Erläuterung:
Der zu ersetzende Teilstring ist im Gesamtstring enthalten. Daher liefert die vor dem Ersetzen durchgeführte Prüfung via strpos() den Rückgabewert true und die Ersetzung via str_replace() wird durchgeführt.
Code:<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($string,"f")!==false){
$test=str_replace("m","g",$string);
}
}
?>
Erläuterung:
Der Teilstring ist im Gesamtstring nicht enthalten, die Überprüfung via strpos() fällt negativ aus und die Ersetzung mittels str_replace() kommt nicht zum Tragen.
Code:<?
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<50;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=str_replace("f","g",$string);
}
?>
Erläuterung:
Dieser Code entspricht dem ersten Beispiel-Script auf dieser Seite mit dem Unterschied, dass der String nun 5.000 Zeichen statt nur 2.000 Zeichen umfasst.
Code:<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<50;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=str_replace("m","g",$string);
}
?>
Erläuterung:
Das Äquivalent zum zweiten Beispiel-Script mit einem 5.000 Zeichen umfassenden String.
Code:<?
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<50;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($string,"f")!==false){
$test=str_replace("f","g",$string);
}
}
?>
Erläuterung:
Dies ist eine Kopie des dritten Beispiel-Scripts mit einem String der Länge 5.000.
Code:<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<50;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($string,"f")!==false){
$test=str_replace("m","g",$string);
}
}
?>
Erläuterung:
Im letzten Beispiel-Script wird der String mit einer Länge von 5.000 Zeichen erfolglos mit strpos() durchsucht. Die Ersetzung via str_replace() wird folglich nicht vorgenommen.
| Requests per second (RPS) | Time per Request (TPR) | Vergleich | ||
| String (2000 Zeichen) enthält Argument, ohne strpos() | 54.61 [#/sec] (mean) | 18.313 [ms] (mean) | 40.6% | 28.9% |
| String (2000 Zeichen) enthält Argument nicht, ohne strpos() | 61.48 [#/sec] (mean) | 16.266 [ms] (mean) | 58.3% | 36.8% |
| String (2000 Zeichen) enthält Argument, mit strpos() | 39.05 [#/sec] (mean) | 25.609 [ms] (mean) | 0.6% | 0.5% |
| String (2000 Zeichen) enthält Argument nicht, mit strpos() | 42.36 [#/sec] (mean) | 23.609 [ms] (mean) | 9.1% | 8.3% |
| String (5000 Zeichen) enthält Argument, ohne strpos() | 54.94 [#/sec] (mean) | 18.203 [ms] (mean) | 41.5% | 29.3% |
| String (5000 Zeichen) enthält Argument nicht, ohne strpos( | 59.76 [#/sec] (mean) | 16.734 [ms] (mean) | 53.9% | 35.0% |
| String (5000 Zeichen) enthält Argument, mit strpos() | 38.83 [#/sec] (mean) | 25.750 [ms] (mean) | ||
| String (5000 Zeichen) enthält Argument nicht, mit strpos() | 42.64 [#/sec] (mean) | 23.453 [ms] (mean) | 9.8% | 8.9% |
Sämtliche Beispiel-Scripte, bei denen der String mittels strpos() durchsucht wurde, benötigen deutlich mehr Ausführzeit als die nur mit str_replace() ohne vorangegangene Überprüfung agierenden Scripte; unabhängig davon, ob der Teilstring im Gesamtstring enthalten ist oder nicht.
Bei Strings entsprechender Länge fällt die Prüfung via strpos() tatsächlich kaum ins Gewicht. Bei Strings mit einer Länge von maximal 5.000 Zeichen kostet sie jedoch nur unnötig Zeit. Es gilt also zu berücksichtigen, dass der zu durchsuchende String deutlich länger als 5.000 Zeichen und die Wahrscheinlichkeit gering sein sollte, dass der zu ersetzende Teilstring im Gesamtstring enthalten ist. In der Praxis wird das selten der Fall sein.
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.