web-dev-qa-db-fra.com

Quel est le meilleur moyen d'ajouter deux chaînes ensemble?

J'ai lu quelque part (j'ai pensé au codinghorror) que c'est une mauvaise pratique d'ajouter des chaînes comme si elles étaient des nombres, car, comme les nombres, les chaînes ne peuvent pas être modifiées. Ainsi, leur ajout crée une nouvelle chaîne. Alors, je me demandais quelle est la meilleure façon d’additionner deux chaînes, lorsque l’on se concentre sur la performance.

Laquelle de ces quatre est la meilleure, ou existe-t-il un autre moyen qui est mieux

//Note that normally at least one of these two strings is variable
$str1 = 'Hello ';
$str2 = 'World!'; 
$output1 = $str1.$str2; //This is said to be bad

$str1 = 'Hello ';
$output2 = $str1.'World!'; //Also bad

$str1 = 'Hello';
$str2 = 'World!';
$output3 = sprintf('%s %s', $str1, $str2); //Good?
//This last one is probaply more common as:
//$output = sprintf('%s %s', 'Hello', 'World!');

$str1 = 'Hello ';
$str2 = '{a}World!';
$output4 = str_replace('{a}', $str1, $str2);

Est-ce même important? 

20
Pim Jager

Vous allez toujours créer une nouvelle chaîne en concaténant deux chaînes ou plus. Ce n'est pas nécessairement «mauvais», mais cela peut avoir des conséquences sur les performances dans certains scénarios (comme des milliers/millions de concaténations dans une boucle étroite). Je ne suis pas un PHP - mec, donc je ne peux vous donner aucun conseil sur la sémantique des différentes façons de concaténer des chaînes, mais pour une concaténation de chaîne unique (ou juste quelques-unes), il suffit de la rendre lisible . Vous n'allez pas voir une performance frappée par un petit nombre d'entre eux.

13
Ed S.

La concaténation de chaînes avec un point est certainement la plus rapide des trois méthodes. Vous allez toujours créer une nouvelle chaîne, que cela vous plaise ou non. Probablement le moyen le plus rapide serait:

$str1 = "Hello";
$str1 .= " World";

Ne les mettez pas entre guillemets comme $result = "$str1$str2"; car cela engendrerait une surcharge supplémentaire pour l'analyse des symboles dans la chaîne.

Si vous allez utiliser ceci uniquement pour la sortie avec echo, utilisez la fonction echo qui vous permet de lui transmettre plusieurs paramètres, car cela ne générera pas de nouvelle chaîne:

$str1 = "Hello";
$str2 = " World";
echo $str1, $str2;

Pour plus d'informations sur la manière dont PHP traite les chaînes interpolées et la concaténation de chaînes consultez le blog de Sarah Goleman .

37
Patrick Glandien

Voici le code de test rapide et sale, pour comprendre les goulots d'étranglement des performances.

Simple concat:

$iterations = 1000000;
$table = 'FOO';
$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = sprintf('DELETE FROM `%s` WHERE `ID` = ?', $table);
}
echo 'single sprintf,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = 'DELETE FROM `' . $table . '` WHERE `ID` = ?';
}
echo 'single concat,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = "DELETE FROM `$table` WHERE `ID` = ?";
}
echo 'single "$str",',(microtime(true) - $time)."\n";

Je reçois ces résultats:

single sprintf,0.66322994232178
single concat,0.18625092506409 <-- winner
single "$str",0.19963216781616

Beaucoup de concats (10):

$iterations = 1000000;
$table = 'FOO';
$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = sprintf('DELETE FROM `%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s` WHERE `ID` = ?', $table, $table, $table, $table, $table, $table, $table, $table, $table, $table);
}
echo 'many sprintf,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = 'DELETE FROM `' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '` WHERE `ID` = ?';
}
echo 'many concat,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = "DELETE FROM `$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table` WHERE `ID` = ?";
}
echo 'many "$str",',(microtime(true) - $time)."\n";

Résultats:

many sprintf,2.0778489112854
many concats,1.535336971283
many "$str",1.0247709751129 <-- winner

En conclusion, il devient évident que la concatte simple via dot (.) Char est la plus rapide. Et dans les cas où vous avez plusieurs concat, la méthode la plus performante consiste à utiliser l’injection directe de chaînes via la syntaxe "injection: $inject".

11
Aleksandr Makov

À moins que sa très grande quantité de texte ne compte vraiment pas.

5
Toby Allen

Comme d'autres l'ont dit, $str1 . $str2 est parfaitement correct dans la plupart des cas, sauf dans les (grandes) boucles.
Notez que vous oubliez certaines solutions:

$output = "$str1$str2";

et pour un grand nombre de chaînes, vous pouvez les placer dans un tableau et utiliser implode () pour en extraire une chaîne.

Oh, et "ajouter des chaînes" a l'air mauvais, ou du moins ambigu. Dans la plupart des langues, nous préférons parler de concaténation de chaînes.

3
PhiLho

Ce n'est pas grave, sauf si utilisé dans une longue boucle. Dans les cas habituels, concentrez-vous sur la lisibilité du code, même si vous avez perdu plusieurs cycles de processeur.

Exemple 1 et 2 sont similaires, je ne pense pas qu'il devrait y avoir beaucoup de différence, ce serait le jeûne de tous. N ° 1 pourrait être légèrement plus rapide.

Exemple 3 sera plus lent, car le format sprintf ('% s% s') doit être analysé.

Exemple 4 effectue le remplacement, ce qui implique une recherche dans une chaîne - une tâche supplémentaire à effectuer prend plus de temps.

Mais premièrement, la concaténation de chaînes est-elle un problème de performances? C'est très improbable, vous devriez profiler le code pour mesurer combien de temps cela prend pour l'exécuter. Ensuite, remplacez la méthode de concaténation par une méthode différente, puis à nouveau.

Si vous l'identifiez comme un problème, essayez de rechercher Google dans la classe constructeur de chaînes php (vous en trouverez) ou écrivez la vôtre.

3
ya23

J'ai trouvé ce message de Google et je pensais avoir fait quelques tests car j'étais curieux de savoir quel en serait le résultat. (Analyse de plus de 10 000 itérations à l'aide d'un indicateur de référence qui soustrait ses propres frais généraux.)

 Dont 2 chaînes 10 chaînes 50 chaînes 
 -------------------------------------------------- --------------
 $ a [] then implode () 2728.20 ps 6.02 μs 22.73 μs 
 $ a. $ a. $ a 496,44 ps 1.48 μs 7.00 μs 
 $ b. = $ 421,40 ps ★ 1,26 µs 5,56 µs 
 ob_start () et echo $ a 2278.16 ps 3.08 μs 8.07 μs 
 "$ a $ a $ a" 482,87 ps 1.21 μs ★ 4,94 μs ★ 
 sprintf () 1543,26 ps 3.21 μs 12.08 μs 

Donc, il n'y a pas grand chose dedans. Probablement bon d'éviter sprintf() et implode() si vous avez besoin de quelque chose qui crie vite, mais il n'y a pas beaucoup de différence entre toutes les méthodes habituelles.

2
Dave Houlbrooke

il existe 3 types d'opérations de jonction de chaînes.

Concaténer, prendre 2 chaînes, allouer la taille mémoire longueur1 + longueur2 et les copier dans la nouvelle mémoire. le plus rapide pour 2 cordes. Cependant, concaténer 10 chaînes nécessite alors 9 opérations de concaténation. La mémoire utilisée est la 1ère chaîne 10 fois, la 2ème chaîne 10 fois, la 3ème chaîne 9 fois, la 4ème chaîne 8 fois, etc. Exécute X + 1 + (X-1) * 2 opérations utilisant plus de mémoire à chaque cycle.

sprintf (array_merge, join, etc.), prenez toutes les chaînes ensemble, additionnez leur longueur, allouez une nouvelle chaîne de la taille somme, puis copiez chaque chaîne à son emplacement respectif. la mémoire utilisée est 2 * longueur de toutes les chaînes initiales, et opérations est 2 * X (chaque longueur, chaque copie)

ob (buffer de sortie) alloue un morceau générique de 4 k et y copie chaque chaîne. mémoire 4k + chaque chaîne initiale, opérations = 2 + X. (début, fin, chaque copie)

Choisissez votre poison. OB est comme utiliser une bombe atomique à mémoire pour joindre deux petites chaînes, mais est très efficace quand il y a beaucoup de jointures, de boucles, de conditions ou que les ajouts sont trop dynamiques pour un sprint propre. joignez quelques chaînes fixes, sprintf, qui fonctionnent mieux pour construire une chaîne à partir de valeurs fixes en même temps.

Je ne sais pas quelle routine php utilise dans cette situation: "$ x $ y $ z", pourrait bien être réduit à un $ x intégré. "". $ y. "". $ z

1
ppostma1

Les conseils que vous avez lus ont peut-être un lien avec la fonction echo, pour laquelle il est plus rapide d’utiliser des virgules, par exemple:

echo $str1, $str2;

Une autre approche consiste à construire une chaîne dans une variable (par exemple, à l'aide de l'opérateur.), Puis à répercuter toute la chaîne à la fin.

Vous pouvez le tester vous-même en utilisant la fonction microtime (vous devrez créer une boucle répétée, par exemple, 1 000 ou 100 000 fois pour que les chiffres soient significatifs). Mais sur les quatre que vous avez publiés, le premier sera probablement le plus rapide. C'est aussi le plus lisible - les autres n'ont pas vraiment de sens par programme.

0
DisgruntledGoat

Ce n'est pas une solution pour 2 chaînes, mais lorsque vous songez à joindre plusieurs chaînes de la meilleure façon comme ça:

$tmp=srray();
for(;;) $tmp[]='some string';
$str=implode('',$tmp);

Il est plus rapide de créer un élément de tableau et de les joindre tous en même temps que de les joindre cent fois.

0
Thinker

Je ne suis pas un gourou PHP, cependant, dans de nombreux autres langages (par exemple, Python), le moyen le plus rapide de créer une longue chaîne à partir de nombreuses chaînes plus petites consiste à ajouter les chaînes que vous souhaitez concaténer à une liste. puis de les rejoindre en utilisant une méthode de jointure intégrée. Par exemple:

$result = array();
array_Push("Hello,");
array_Push("my");
array_Push("name");
array_Push("is");
array_Push("John");
array_Push("Doe.");
$my_string = join(" ", $result);

Si vous construisez une énorme chaîne dans une boucle serrée, le moyen le plus rapide de le faire consiste à ajouter au tableau, puis à rejoindre le tableau à la fin.

Remarque: Toute la discussion repose sur les performances d'un array_Push. Vous devez ajouter vos chaînes à un list pour que cela soit efficace sur de très grandes chaînes. En raison de mon exposition limitée à php, je ne sais pas si une telle structure est disponible ou si le tableau de php est rapide pour ajouter de nouveaux éléments.

0
shadanan

Pendant près de 2 ans après le dernier message dans ce fil de discussion, je pense que la solution ci-dessous est peut-être la plus rapide pour un grand nombre de boucles serrées:

ob_start();

echo $str1;
echo $str2;
.
.
.
echo $str_n;

$finalstr = ob_get_clean();

Cette méthode garantit un stockage à plat de toutes les chaînes et aucun frais de traitement ou de concaténation. Avec la ligne de code finale, vous obtenez également la totalité du tampon. Vous pouvez exécuter des boucles en toute sécurité au lieu d’échos indépendants.

0
Eric Joyce