Single quotes vs. double quotes in PHP Strings
Ich glaube dieses Thema ist schon an vielen anderen Stellen ausführlich diskutiert worden. Warum also mein Beitrag?
Ich wollte verschiedene Methoden testen, wie Strings verwendet werden und habe einfach keine Beiträge gefunden, die all diese Tests gemeinsam enthielten.
Es stellte sich die Frage, ob in PHP Strings besser single quotes, also einfache Anführungszeichen ( ‚ ) oder double quotes, also doppelte Anführungszeichen ( “ ) verwendet werden sollten.
Getestet habe ich unter Debian mit PHP 5.3.3-6 CLI.
Verglichen habe ich:
- In einen String (double quotes) eingebettete Variablen
- In einen String (double quotes) eingebettete Variablen mit curly brackets { }
- Einen String (double quotes) mit Variablen durch Verkettung mit Punkten
- Einen String (single quotes) mit Variablen durch Verkettung mit Punkten
- Einen String (double quotes) ohne Variablen
- Einen String (single quotes) ohne Variablen
Die ersten vier Tests liefen in einer Schleife mit 2.500.000 Durchläufen, die letzten beiden mit 25.000.000 Durchläufen um eine nicht zu geringe Dauer zu haben.
Hier nun das Testskript:
[pastacode lang=“php“ message=“PHP“ highlight=““ provider=“manual“]
function currentTime(){
$mtime = microtime();
$mtime = explode(' ', $mtime);
$mtime = $mtime[1] + $mtime[0];
return $mtime;
}
function rnd_str() {
$str = '';
$len = mt_rand(8,225);
for($i = 1; $i < = $len; $i++) $str .= substr('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ-__', mt_rand(0, 55), 1);
return $str;
}
$part1 = rnd_str();
$part2 = rnd_str();
$part3 = rnd_str();
$part4 = rnd_str();
$cnt = 2500000;
print "Doing $cnt loops (" . ($cnt * 10) . " for strings without vars).\n";
$start = currentTime();
for($i = 0; $i < $cnt; $i++) {
$string = "This is a $part1 string that contains $part2 other strings with $part3 different methods of concatenation $part4";
}
$dur = currentTime() - $start;
print "Double quotes and no dots took " . $dur . " seconds.\n";
$start = currentTime();
for($i = 0; $i < $cnt; $i++) {
$string = "This is a {$part1} string that contains {$part2} other strings with {$part3} different methods of concatenation {$part4}";
}
$dur = currentTime() - $start;
print "Double quotes and curlies took " . $dur . " seconds.\n";
$start = currentTime();
for($i = 0; $i < $cnt; $i++) {
$string = "This is a " . $part1 . " string that contains " . $part2 . " other strings with " . $part3 . " different methods of concatenation " . $part4;
}
$dur = currentTime() - $start;
print "Double quotes and dots took " . $dur . " seconds.\n";
$start = currentTime();
for($i = 0; $i < $cnt; $i++) {
$string = 'This is a ' . $part1 . ' string that contains ' . $part2 . ' other strings with ' . $part3 . ' different methods of concatenation ' . $part4;
}
$dur = currentTime() - $start;
print "Single quotes and dots took " . $dur . " seconds.\n";
$cnt*=10;
$start = currentTime();
for($i = 0; $i < $cnt; $i++) {
$string = "This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation";
}
$dur = currentTime() - $start;
print "Double quotes string only took " . $dur . " seconds.\n";
$start = currentTime();
for($i = 0; $i < $cnt; $i++) {
$string = 'This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation This is a string that contains no other strings with different methods of concatenation';
}
$dur = currentTime() - $start;
print "Single quotes string only took " . $dur . " seconds.\n";
[/pastacode]
Das Ergebnis (ich habe es mehrfach getestet, die Ergebnisse sind immer ähnlich):
[pastacode lang=“bash“ message=“Kommandozeile“ highlight=““ provider=“manual“]
php test3.php
# Doing 2500000 loops (25000000 for strings without vars).
# Double quotes and no dots took 3.7328441143 seconds.
# Double quotes and curlies took 4.21458005905 seconds.
# Double quotes and dots took 5.5920958519 seconds.
# Single quotes and dots took 5.64905500412 seconds.
# Double quotes string only took 9.65513300896 seconds.
# Single quotes string only took 9.47072196007 seconds.
[/pastacode]
Obwohl die Ergebnisse immer ein bisschen schwanken lassen sich zumindest in diesem Test folgende Schlüsse ziehen:
- Werden keine Variablen oder Spezialzeichen wie \n im String verwendet, ist es im Endeffekt egal welche Quotes verwendet werden. Allerdings empfiehlt es sich meiner Meinung nach immer single quotes zu verwenden, wenn man mit HTML Strings arbeitet (trotz Trennung von Code und Layout). So verhindert man im HTML Code \“ verwenden zu müssen.
- Bei der Verwendung von Variablen ist es bei den Tests performanter gewesen sie in den String einzubetten, also „abc $variable xyz“ statt „abc“ . $variable . „xyz“ zu verwenden. Der Übersichtlichkeit halber würde ich dann jedoch „abc {$variable} xyz“, also die Variante mit curly brackets, verwenden auch wenn sie in den Tests minimal langsamer war. Werden Array-Variablen im String benötigt, so ist meiner Ansicht nach auch „abc {$arr[‚index‘]} xyz“ der Variante ‚abc ‚ . $arr[‚index‘] . ‚ xyz‘ vorzuziehen. Dies hätte ich vor den Tests nicht unbedingt erwartet und der Übersichtlichkeit halber wohl anders gemacht.
Nachtrag:
Sören hat mich auf einen Blogbeitrag von Marko Röper aufmerksam gemacht.
Ich habe mich gefragt, wieso seine Ergebnisse sich so extrem von meinen unterscheiden. Also habe ich sein Testscript genommen und unverändert bei mir laufen lassen.
Das Ergebnis:
php test4.php # float(0.366719007492) # float(0.251353025436)
Also ist die Variante mit den Single Quotes und den . als Verkettung schneller. Nun kommt das große ABER:
Ändere ich in der Testdatei den Inhalt der Variablen von
$hallo = "Hallo";
in
$hallo = "HalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHalloHallo";
und die Zuweisungen in den Schleifen von
$hallo_welt = "$hallo Welt."; // bzw. $hallo_welt = $hallo.' Welt.';
in
$hallo_welt = "$hallo Welt $hallo."; // bzw. $hallo_welt = $hallo.' Welt'.$hallo.'.';
dann ergibt sich folgendes Ergebnis:
php test5.php # float(0.747298955917) # float(1.00494885445)
Das heißt also: Je mehr Variablen im String verwendet werden und je länger der Inhalt in der Variable ist, desto langsamer wird die Verkettung mit Punkten im Vergleich zu der Einbettung in einen double quote String.
Und wirklich: Je öfter man die Variable in den String einfügt und den Inhalt verlängert, desto extremer wird das Verhältnis.
Also nicht nur darauf achten ob, sondern auch wie viele und welche Variablen verwendet werden. Das macht die Entscheidung für single oder double quotes nicht unbedingt leichter.
Es ist schön über eine sorgfältig gemachten Messung zu lesen. Aber, wie sagte schon Knuth:
Es macht keinen Sinn die String-Schreibweise zu „optimieren“, wenn das Programm gar keine Performance-Probleme hat. Da kann man höchstens etwas verschlechtern, statt zu verbessern, z.B. die Lesbarkeit und Wartbarkeit des Programmes mindern. Falls es Performance-Probleme gibt, falls die Antwortzeiten für die UserInnen nicht akzeptabel sind, dann muss man erst herausfinden wo das Problem liegt.
Im Grundsatz hast du Recht, allerdings bin ich schon der Ansicht, dass man vor Beginn der Arbeiten die Vor- und Nachteile einzelner Methoden kennen sollte – nicht nur auf dieses Thema bezogen. Wenn man von Beginn an darauf hofft viele Zugriffe zu haben ist es ja auch sinnvoll direkt möglichst performant zu programmieren.
Gerade weil dieses Thema so oft und kontrovers diskutiert wird und wie ich finde viele Artikel (wie auch der im Nachtrag verlinkte) irgendwie nur „die halbe Wahrheit“ enthielten, dachte ich es könnte sinnvoll sein dies mal näher zu beleuchten.
Hallo Marius, danke für diesen interessanten Artikel. Ich bin gerade dabei, etwas PHP zu lernen und fand auf der Suche nach Single Double Quotes Points PHP Deinen Artikel. Ich fand ihn sehr hilfreich, da ich nun weiß, dass allerhöchstens Performance-Probleme den Unterschied ausmachen. Ich habe mir nun vorerst angewöhnt, immer Singlequotes am Anfang und Ende des Strings zu verwenden und innen Punkte zum Wechseln zwischen Text und PHP. Ich finde das wesentlich übersichtlicher als ständig über Escapes und innenliegende Double Single Quotes nachdenken zu müssen. Sollte ich wirklich mal an den Punkt kommen, wo meine Scripte merkliche Performance-Einbußen mit sich bringen, werde die dritte Alternative mal ausprobieren. Auf jeden Fall vielen Dank für diese anschauliche und hilfreiche Aufklärung. LG <"}))}~