Nein, es gibt keinen Typ von Stringbuilder-Klasse in PHP, da Strings veränderlich sind.
Davon abgesehen gibt es verschiedene Möglichkeiten, einen String zu erstellen, je nachdem, was Sie tun.
Echo akzeptiert beispielsweise durch Kommas getrennte Token für die Ausgabe.
echo 'one', 'two';
echo 'one';
echo 'two';
Dies bedeutet, dass Sie eine komplexe Zeichenfolge ausgeben können, ohne tatsächlich eine Verkettung zu verwenden, die langsamer wäre
echo 'one', 'two';
echo 'one' . 'two';
Wenn Sie diese Ausgabe in einer Variablen erfassen müssen, können Sie dies mit den Ausgabepufferfunktionen tun .
Auch die Array-Leistung von PHP ist wirklich gut. Wenn Sie so etwas wie eine durch Kommas getrennte Liste von Werten erstellen möchten, verwenden Sie einfach implode ()
$values = array( 'one', 'two', 'three' );
$valueList = implode( ', ', $values );
Stellen Sie schließlich sicher, dass Sie sich mit dem Zeichenfolgentyp von PHP und den verschiedenen Trennzeichen sowie deren Auswirkungen vertraut gemacht haben.
$x = 5; echo "x = $x";
würde drucken,x = 5
während$x = 5; echo 'x = $x';
drucken würdex = $x
.Ich war neugierig und habe einen Test durchgeführt. Ich habe den folgenden Code verwendet:
<?php ini_set('memory_limit', '1024M'); define ('CORE_PATH', '/Users/foo'); define ('DS', DIRECTORY_SEPARATOR); $numtests = 1000000; function test1($numtests) { $CORE_PATH = '/Users/foo'; $DS = DIRECTORY_SEPARATOR; $a = array(); $startmem = memory_get_usage(); $a_start = microtime(true); for ($i = 0; $i < $numtests; $i++) { $a[] = sprintf('%s%sDesktop%sjunk.php', $CORE_PATH, $DS, $DS); } $a_end = microtime(true); $a_mem = memory_get_usage(); $timeused = $a_end - $a_start; $memused = $a_mem - $startmem; echo "TEST 1: sprintf()\n"; echo "TIME: {$timeused}\nMEMORY: $memused\n\n\n"; } function test2($numtests) { $CORE_PATH = '/Users/shigh'; $DS = DIRECTORY_SEPARATOR; $a = array(); $startmem = memory_get_usage(); $a_start = microtime(true); for ($i = 0; $i < $numtests; $i++) { $a[] = $CORE_PATH . $DS . 'Desktop' . $DS . 'junk.php'; } $a_end = microtime(true); $a_mem = memory_get_usage(); $timeused = $a_end - $a_start; $memused = $a_mem - $startmem; echo "TEST 2: Concatenation\n"; echo "TIME: {$timeused}\nMEMORY: $memused\n\n\n"; } function test3($numtests) { $CORE_PATH = '/Users/shigh'; $DS = DIRECTORY_SEPARATOR; $a = array(); $startmem = memory_get_usage(); $a_start = microtime(true); for ($i = 0; $i < $numtests; $i++) { ob_start(); echo $CORE_PATH,$DS,'Desktop',$DS,'junk.php'; $aa = ob_get_contents(); ob_end_clean(); $a[] = $aa; } $a_end = microtime(true); $a_mem = memory_get_usage(); $timeused = $a_end - $a_start; $memused = $a_mem - $startmem; echo "TEST 3: Buffering Method\n"; echo "TIME: {$timeused}\nMEMORY: $memused\n\n\n"; } function test4($numtests) { $CORE_PATH = '/Users/shigh'; $DS = DIRECTORY_SEPARATOR; $a = array(); $startmem = memory_get_usage(); $a_start = microtime(true); for ($i = 0; $i < $numtests; $i++) { $a[] = "{$CORE_PATH}{$DS}Desktop{$DS}junk.php"; } $a_end = microtime(true); $a_mem = memory_get_usage(); $timeused = $a_end - $a_start; $memused = $a_mem - $startmem; echo "TEST 4: Braced in-line variables\n"; echo "TIME: {$timeused}\nMEMORY: $memused\n\n\n"; } function test5($numtests) { $a = array(); $startmem = memory_get_usage(); $a_start = microtime(true); for ($i = 0; $i < $numtests; $i++) { $CORE_PATH = CORE_PATH; $DS = DIRECTORY_SEPARATOR; $a[] = "{$CORE_PATH}{$DS}Desktop{$DS}junk.php"; } $a_end = microtime(true); $a_mem = memory_get_usage(); $timeused = $a_end - $a_start; $memused = $a_mem - $startmem; echo "TEST 5: Braced inline variables with loop-level assignments\n"; echo "TIME: {$timeused}\nMEMORY: $memused\n\n\n"; } test1($numtests); test2($numtests); test3($numtests); test4($numtests); test5($numtests);
... und bekam die folgenden Ergebnisse. Bild angehängt. Sprintf ist eindeutig der am wenigsten effiziente Weg, sowohl hinsichtlich des Zeit- als auch des Speicherverbrauchs. BEARBEITEN: Zeigen Sie das Bild auf einer anderen Registerkarte an, es sei denn, Sie haben Adlersicht.
quelle
test2
aber ersetzen.
durch,
(natürlich ohne Ausgabepuffer)StringBuilder analog wird in PHP nicht benötigt.
Ich habe ein paar einfache Tests gemacht:
in PHP:
$iterations = 10000; $stringToAppend = 'TESTSTR'; $timer = new Timer(); // based on microtime() $s = ''; for($i = 0; $i < $iterations; $i++) { $s .= ($i . $stringToAppend); } $timer->VarDumpCurrentTimerValue(); $timer->Restart(); // Used purlogic's implementation. // I tried other implementations, but they are not faster $sb = new StringBuilder(); for($i = 0; $i < $iterations; $i++) { $sb->append($i); $sb->append($stringToAppend); } $ss = $sb->toString(); $timer->VarDumpCurrentTimerValue();
in C # (.NET 4.0):
const int iterations = 10000; const string stringToAppend = "TESTSTR"; string s = ""; var timer = new Timer(); // based on StopWatch for(int i = 0; i < iterations; i++) { s += (i + stringToAppend); } timer.ShowCurrentTimerValue(); timer.Restart(); var sb = new StringBuilder(); for(int i = 0; i < iterations; i++) { sb.Append(i); sb.Append(stringToAppend); } string ss = sb.ToString(); timer.ShowCurrentTimerValue();
Ergebnisse:
10000 Iterationen:
1) , PHP, gewöhnliche Verkettung: ~ 6 ms
2) PHP, unter Verwendung von String: ~ 5 ms
3) C #, gewöhnliche Verkettung: ~ 520ms
4) C #, unter Verwendung von String: ~ 1ms
100000 Iterationen:
1) PHP, normale Verkettung: ~ 63 ms
2) PHP mit StringBuilder: ~ 555 ms
3) C #, normale Verkettung: ~ 91000 ms // !!!
4) C # mit StringBuilder: ~ 17ms
quelle
Wenn Sie einen zeitgesteuerten Vergleich durchführen, sind die Unterschiede so gering, dass sie nicht sehr relevant sind. Es würde mehr bedeuten, sich für die Wahl zu entscheiden, die das Lesen und Verstehen Ihres Codes erleichtert.
quelle
Ich weiß wovon du sprichst. Ich habe gerade diese einfache Klasse erstellt, um die Java StringBuilder-Klasse zu emulieren.
class StringBuilder { private $str = array(); public function __construct() { } public function append($str) { $this->str[] = $str; } public function toString() { return implode($this->str); } }
quelle
append
Funktion können Sie hinzufügenreturn $this;
, um die Methodenverkettung zu ermöglichen :$sb->append("one")->append("two");
.PHP-Strings sind veränderbar. Sie können bestimmte Zeichen wie folgt ändern:
$string = 'abc'; $string[2] = 'a'; // $string equals 'aba' $string[3] = 'd'; // $string equals 'abad' $string[5] = 'e'; // $string equals 'abad e' (fills character(s) in between with spaces)
Und Sie können Zeichen wie folgt an eine Zeichenfolge anhängen:
$string .= 'a';
quelle
Ich habe den Code am Ende dieses Beitrags geschrieben, um die verschiedenen Formen der Zeichenfolgenverkettung zu testen, und sie sind wirklich alle in Bezug auf Speicher- und Zeitabdruck fast genau gleich.
Die beiden wichtigsten Methoden, die ich verwendet habe, bestehen darin, Zeichenfolgen miteinander zu verknüpfen, ein Array mit Zeichenfolgen zu füllen und diese dann zu implodieren. Ich habe 500 Zeichenfolgen mit einer 1-MB-Zeichenfolge in PHP 5.6 hinzugefügt (das Ergebnis ist also eine 500-MB-Zeichenfolge). Bei jeder Iteration des Tests waren alle Speicher- und Zeitabdrücke sehr, sehr eng (bei ~ $ IterationNumber * 1MB). Die Laufzeit beider Tests betrug nacheinander 50,398 Sekunden und 50,843 Sekunden, was höchstwahrscheinlich innerhalb akzeptabler Fehlergrenzen liegt.
Die Speicherbereinigung von Zeichenfolgen, auf die nicht mehr verwiesen wird, scheint ziemlich unmittelbar zu sein, auch ohne jemals den Gültigkeitsbereich zu verlassen. Da die Zeichenfolgen veränderbar sind, wird nachträglich kein zusätzlicher Speicher benötigt.
Die folgenden Tests haben jedoch gezeigt, dass sich die maximale Speichernutzung unterscheidet, während die Zeichenfolgen verkettet werden.
$OneMB=str_repeat('x', 1024*1024); $Final=$OneMB.$OneMB.$OneMB.$OneMB.$OneMB; print memory_get_peak_usage();
Ergebnis = 10.806.800 Bytes (~ 10 MB ohne den anfänglichen PHP-Speicherbedarf)
$OneMB=str_repeat('x', 1024*1024); $Final=implode('', Array($OneMB, $OneMB, $OneMB, $OneMB, $OneMB)); print memory_get_peak_usage();
Ergebnis = 6.613.320 Bytes (~ 6 MB ohne den anfänglichen PHP-Speicherbedarf)
Es gibt also tatsächlich einen Unterschied, der bei sehr sehr großen Zeichenfolgenverkettungen in Bezug auf den Speicher von Bedeutung sein kann (ich habe solche Beispiele beim Erstellen sehr großer Datenmengen oder SQL-Abfragen gefunden).
Aber auch diese Tatsache ist je nach Daten umstritten. Das Verketten eines Zeichens mit einer Zeichenfolge, um 50 Millionen Bytes (also 50 Millionen Iterationen) zu erhalten, dauerte beispielsweise in 5,97 Sekunden maximal 50.322.512 Bytes (~ 48 MB). Dabei wurden für die Array-Methode 7.337.107.176 Byte (~ 6,8 GB) verwendet, um das Array in 12,1 Sekunden zu erstellen. Anschließend wurden zusätzliche 4,32 Sekunden benötigt, um die Zeichenfolgen aus dem Array zu kombinieren.
Egal ... das Folgende ist der Benchmark-Code, den ich am Anfang erwähnt habe und der zeigt, dass die Methoden ziemlich gleich sind. Es gibt eine hübsche HTML-Tabelle aus.
<? //Please note, for the recursion test to go beyond 256, xdebug.max_nesting_level needs to be raised. You also may need to update your memory_limit depending on the number of iterations //Output the start memory print 'Start: '.memory_get_usage()."B<br><br>Below test results are in MB<br>"; //Our 1MB string global $OneMB, $NumIterations; $OneMB=str_repeat('x', 1024*1024); $NumIterations=500; //Run the tests $ConcatTest=RunTest('ConcatTest'); $ImplodeTest=RunTest('ImplodeTest'); $RecurseTest=RunTest('RecurseTest'); //Output the results in a table OutputResults( Array('ConcatTest', 'ImplodeTest', 'RecurseTest'), Array($ConcatTest, $ImplodeTest, $RecurseTest) ); //Start a test run by initializing the array that will hold the results and manipulating those results after the test is complete function RunTest($TestName) { $CurrentTestNums=Array(); $TestStartMem=memory_get_usage(); $StartTime=microtime(true); RunTestReal($TestName, $CurrentTestNums, $StrLen); $CurrentTestNums[]=memory_get_usage(); //Subtract $TestStartMem from all other numbers foreach($CurrentTestNums as &$Num) $Num-=$TestStartMem; unset($Num); $CurrentTestNums[]=$StrLen; $CurrentTestNums[]=microtime(true)-$StartTime; return $CurrentTestNums; } //Initialize the test and store the memory allocated at the end of the test, with the result function RunTestReal($TestName, &$CurrentTestNums, &$StrLen) { $R=$TestName($CurrentTestNums); $CurrentTestNums[]=memory_get_usage(); $StrLen=strlen($R); } //Concatenate 1MB string over and over onto a single string function ConcatTest(&$CurrentTestNums) { global $OneMB, $NumIterations; $Result=''; for($i=0;$i<$NumIterations;$i++) { $Result.=$OneMB; $CurrentTestNums[]=memory_get_usage(); } return $Result; } //Create an array of 1MB strings and then join w/ an implode function ImplodeTest(&$CurrentTestNums) { global $OneMB, $NumIterations; $Result=Array(); for($i=0;$i<$NumIterations;$i++) { $Result[]=$OneMB; $CurrentTestNums[]=memory_get_usage(); } return implode('', $Result); } //Recursively add strings onto each other function RecurseTest(&$CurrentTestNums, $TestNum=0) { Global $OneMB, $NumIterations; if($TestNum==$NumIterations) return ''; $NewStr=RecurseTest($CurrentTestNums, $TestNum+1).$OneMB; $CurrentTestNums[]=memory_get_usage(); return $NewStr; } //Output the results in a table function OutputResults($TestNames, $TestResults) { global $NumIterations; print '<table border=1 cellspacing=0 cellpadding=2><tr><th>Test Name</th><th>'.implode('</th><th>', $TestNames).'</th></tr>'; $FinalNames=Array('Final Result', 'Clean'); for($i=0;$i<$NumIterations+2;$i++) { $TestName=($i<$NumIterations ? $i : $FinalNames[$i-$NumIterations]); print "<tr><th>$TestName</th>"; foreach($TestResults as $TR) printf('<td>%07.4f</td>', $TR[$i]/1024/1024); print '</tr>'; } //Other result numbers print '<tr><th>Final String Size</th>'; foreach($TestResults as $TR) printf('<td>%d</td>', $TR[$NumIterations+2]); print '</tr><tr><th>Runtime</th>'; foreach($TestResults as $TR) printf('<td>%s</td>', $TR[$NumIterations+3]); print '</tr></table>'; } ?>
quelle
Ja. Tun sie. Wenn Sie beispielsweise mehrere Zeichenfolgen zusammen wiedergeben möchten, verwenden Sie
Anstatt von
um es etwas schneller zu bekommen.quelle
Erstens, wenn Sie nicht möchten, dass die Zeichenfolgen verkettet werden, tun Sie es nicht: Es wird immer schneller gehen
echo $a,$b,$c;
als
echo $a . $b . $c;
Zumindest in PHP5 ist die Verkettung von Zeichenfolgen jedoch sehr schnell, insbesondere wenn nur ein Verweis auf eine bestimmte Zeichenfolge vorhanden ist. Ich denke, der Dolmetscher verwendet
StringBuilder
intern eine ähnliche Technik.quelle
Wenn Sie Variablenwerte in PHP-Zeichenfolgen einfügen, ist die Inline-Variableneinbeziehung meines Erachtens etwas schneller (das ist nicht der offizielle Name - ich kann mich nicht erinnern, was ist).
$aString = 'oranges'; $compareString = "comparing apples to {$aString}!"; echo $compareString comparing apples to oranges!
Muss in doppelten Anführungszeichen stehen, um zu funktionieren. Funktioniert auch für Array-Mitglieder (dh
echo "You requested page id {$_POST['id']}";
)
quelle
Ich bin gerade auf dieses Problem gestoßen:
$ str. = 'String-Verkettung. ';
vs.
$ str = $ str. 'String-Verkettung. ';
Hier scheint bisher niemand dies verglichen zu haben. Und die Ergebnisse sind mit 50.000 Iterationen und PHP 7.4 ziemlich verrückt:
Zeichenfolge 1: 0,0013918876647949
Zeichenfolge 2: 1.1183910369873
Faktor: 803 !!!
$currentTime = microtime(true); $str = ''; for ($i = 50000; $i > 0; $i--) { $str .= 'String concatenation. '; } $currentTime2 = microtime(true); echo "String 1: " . ( $currentTime2 - $currentTime); $str = ''; for ($i = 50000; $i > 0; $i--) { $str = $str . 'String concatenation. '; } $currentTime3 = microtime(true); echo "<br>String 2: " . ($currentTime3 - $currentTime2); echo "<br><br>Faktor: " . (($currentTime3 - $currentTime2) / ( $currentTime2 - $currentTime));
Kann jemand das bestätigen? Ich bin darauf gestoßen, weil ich einige Zeilen aus einer großen Datei gelöscht habe, indem ich die gewünschten Zeilen gelesen und nur wieder an eine Zeichenfolge angehängt habe.
Die Verwendung von. = Hat hier alle meine Probleme gelöst. Bevor ich eine Auszeit bekam!
quelle
Keine solche Einschränkung in PHP, PHP kann Strng mit dem Punkt (.) Operator verketten
$a="hello "; $b="world"; echo $a.$b;
gibt "Hallo Welt" aus
quelle