String-Interpolation für einfache Anwendungsfälle

Als Softwareentwickler verbringen wir viel Zeit damit Code zu lesen, der von uns und/oder anderen Personen geschrieben wurde. Gut strukturierter und wenig komplexer Code lässt sich einfacher lesen und besser/schneller verstehen. Immer wieder stoße ich auf Codezeilen, die meiner Meinung nach unnötig kompliziert geschrieben wurden. Statt String-Interpolation zu verwenden, nutzt man bspw. mehrmals in einer Zeile den Verknüpfungsoperator oder sprintf(). Das kann zu langen Zeilen mit vielen Unterbrechungen und zu schlechter lesbarem Code führen.

Nachfolgend bauen wir eine URL aus ihren Einzelbestandteilen zusammen und nutzen dafür die drei genannten Varianten:

// String-Interpolation $url = "$scheme://$host:$port/$path?$query"; // String-Concatenation $url = $scheme . '://' . $host . ':' . $port . '/' . $path . '?' . $query; // sprintf() $url = sprintf("%s://%s:%s/%s?%s", $scheme, $host, $port, $path, $query);
Code-Sprache: PHP (php)

Schauen wir uns zunächst die String-Interpolation an. Der String wird an keiner Stelle zerteilt. Er ist kurz und auf einen Blick greifbar. Es sind keine zusätzlichen Zeichen oder Operationen involviert. Das Einsetzen der Variablen an entsprechender Stelle ist präzise und deutlich. Meiner Meinung nach ist dies die lesbarste Variante. In einem Test stellte sie sich auch als effizienteste Variante raus.

Die Variante mit String-Concatenation ist am längsten. Die hinzugefügten Leerzeichen und Punkte und die Zerteilung des Literals in mehrere Einzelteile reduziert für mich die Lese- und Schreibgeschwindigkeit. Diese Variante war am zweiteffizientesten.

Bei der Variante mit sprintf() wird der String mit Platzhaltern %s als erstes Argument übergeben. Die Reihenfolge, in der Variablen eingesetzt werden, definiert sich durch die Reihenfolge, in der wir sie an sprintf() übergeben. Im Gegensatz zu den anderen Varianten wird nicht auf dem ersten Blick klar, an welcher Stelle welche Variable eingesetzt wird. In unserem Beispiel können wir das mit Durchzählen erreichen. Diese Variante stellte sich als die ineffizienteste heraus.

Effizienz-Test

Es handelt sich um einen theoretischen Test, der nicht unbedingt auf ein Echtwelt-Szenario abbildbar ist. Für den Test wurde PHP 8.1.5 auf Windows 11 verwendet. Die Menge an durchgeführten String-Interpolationen, -Concatenationen und sprintf() sind explizit sehr hoch gewählt worden, um die Abweichung zu minimieren.

Nachfolgend schauen wir uns die Ergebnisse und den dazugehörigen Code an:

VarianteDauer (Sekunden)%
Interpolation10,291062116623100,00 %
Concatenation18,851090192795183,18 %
sprintf()21,245018005371206,44 %
<?php define('ROUNDS', 100000000); $scheme = 'https'; $host = 'blog.angelocali.de'; $port = '443'; $path = 'this-is-the-way'; $query = 'really=true'; function warmup() { for ($i = 0; $i < ROUNDS; $i++) { // I want my CPU to spin-up before the real test starts $url = bin2hex(random_bytes(16)); } } function testInterpolation() { global $scheme, $host, $port, $path, $query; for ($i = 0; $i < ROUNDS; $i++) { $url = "$scheme://$host:$port/$path?$query"; } } function testConcatenation() { global $scheme, $host, $port, $path, $query; for ($i = 0; $i < ROUNDS; $i++) { $url = $scheme . '://' . $host . ':' . $port . '/' . $path . '?' . $query; } } function testSprintf() { global $scheme, $host, $port, $path, $query; for ($i = 0; $i < ROUNDS; $i++) { $url = sprintf("%s://%s:%s/%s?%s", $scheme, $host, $port, $path, $query); } } function benchmark($fn) { $start = microtime(true); $fn(); $timePassed = microtime(true) - $start; echo "$fn: $timePassed\n"; } benchmark('warmup'); benchmark('testInterpolation'); benchmark('testConcatenation'); benchmark('testSprintf');
Code-Sprache: HTML, XML (xml)

Wie wir sehen konnten, lohnt es sich bei einfachen Anwendungsfällen die String-Interpolation zu verwenden, da sie die effizienteste und lesbarste der vorgestellten Varianten ist.

Welche Variante bevorzugt ihr und wie ist eure Meinung zu dem Thema?

3 Kommentare

  1. Das muss einen nicht wundern – schliesslich muss bei *printf auch erstmal der String auf zu interpolierende Werte hin geparsed werden. Das fällt ja bei concat weg. Auf der anderen Seite haben die *printf Befehle den großen Vorteil der sauberen Typ-Konvertierung & Formatierung.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.