Perché usare la funzione sprintf in PHP?


188

Sto cercando di saperne di più sulla funzione PHP sprintf () ma php.net non mi ha aiutato molto perché sono ancora confuso, perché dovresti usarlo?

Dai un'occhiata al mio esempio di seguito.

Perché usare questo:

$output = sprintf("Here is the result: %s for this date %s", $result, $date);

Quando questo fa lo stesso ed è più facile scrivere IMO:

$output = 'Here is the result: ' .$result. ' for this date ' .$date;

Mi sto perdendo qualcosa qui?


40
+1, buona domanda. Lo uso raramente da solo, quindi sono interessato a vedere le risposte.
Zombat,

6
Nota che i tuoi due esempi non sono equivalenti: il primo assegna semplicemente il risultato $output, mentre il secondo echolo è.
Daniel Pryden,

Lo uso personalmente quando concatengo molte cose. È solo allora che lo trovo utile, soprattutto per la leggibilità.
AlexMorley-Finch,

Risposte:


130

sprintf ha tutte le capacità di formattazione della stampa originale, il che significa che puoi fare molto di più che inserire semplicemente valori variabili nelle stringhe.

Ad esempio, specificare il formato numerico (esadecimale, decimale, ottale), il numero di decimali, il riempimento e altro. Google per printf e troverai molti esempi. L' articolo di Wikipedia su printf dovrebbe iniziare.


46
Anni fa ho scritto una bella funzione per i numeri zero padding. Usato per anni prima di rendermi conto che potrei semplicemente faresprintf('%03d', $num)
DisgruntledGoat

5
PHP sprintf ha tutte le capacità di formattazione ... in realtà ne manca una importante, %,8dad esempio per ottenere 8 cifre allineate correttamente e virgole separate. L'uso number_formatè meno conveniente in uno printfstile.
e2-e4,

3
@DisgruntledGoat Puoi scomporre quella stringa di formattazione ('% 03d')? Penso che sarebbe davvero utile. Grazie.
Mr. Smee,

3
È inoltre possibile ripetere e riordinare gli argomenti da visualizzare. es. sprintf('%2$s %1$s, my name is also %1$s.', 'World', 'Hello');risultante inHello World, my name is also World.
fyrye

77

Esistono molti casi d'uso per sprintf, ma un modo in cui li utilizzo è la memorizzazione di una stringa come questa: 'Ciao, il mio nome è% s' in un database o come costante in una classe PHP. In questo modo quando voglio usare quella stringa posso semplicemente fare questo:

$name = 'Josh';
// $stringFromDB = 'Hello, My Name is %s';
$greeting = sprintf($stringFromDB, $name);
// $greetting = 'Hello, My Name is Josh'

In sostanza, consente una certa separazione nel codice. Se uso "Ciao, il mio nome è% s" in molti punti del mio codice, posso cambiarlo in "% s è il mio nome" in un punto e si aggiorna dappertutto in modo automatico, senza dover andare in ogni istanza e spostarmi concatenazioni.


8
Questo. Ora aggiungi argomenti numerati e traduzioni:]
Konerak,

46

Un altro uso di sprintfè nelle applicazioni localizzate in quanto gli argomenti sprintfnon devono essere nell'ordine in cui compaiono nella stringa di formato.

Esempio:

$color = 'blue';
$item = 'pen';

sprintf('I have a %s %s', $color, $item);

Ma una lingua come il francese ordina le parole in modo diverso:

$color = 'bleu';
$item = 'stylo';

sprintf('J\'ai un %2$s %1$s', $color, $item);

(Sì, il mio francese fa schifo: ho imparato il tedesco a scuola!)

In realtà, useresti gettext per memorizzare le stringhe localizzate ma hai l'idea.



37

È più facile da tradurre.

echo _('Here is the result: ') . $result . _(' for this date ') . $date;

Le stringhe di traduzione (gettext) sono ora:

  • Ecco il risultato:
  • per questa data

Se tradotto in un'altra lingua, potrebbe essere impossibile o risulta in frasi molto strane.

Ora se hai

echo sprintf(_("Here is the result: %s for this date %s"), $result, $date);

Le stringhe di traduzione (gettext) sono ora:

  • Ecco il risultato:% s per questa data% s

Il che ha molto più senso ed è molto più flessibile tradurre in altre lingue


1
Vedo dove questo sarebbe molto utile +1
JasonDavis

6
Sebbene per le traduzioni sarebbe probabilmente meglio usare gli echo sprintf(_("Here is the result: %1$s for this date %2$s"), $result, $date);For the date %2$s, the result is %1$s
identificatori di

1
Anche se non sono presenti nella stringa originale, puoi inserirli nella traduzione e funzioneranno.
extra il

17

La migliore ragione che ho scoperto è che ti consente di inserire tutte le stringhe di lingua nel tuo file di lingua dove le persone possono tradurle e ordinarle secondo necessità - eppure sai ancora che, indipendentemente dal formato in cui si trova la stringa, desideri mostrare il nome dell'utente.

Ad esempio, il tuo sito dirà "Bentornato [[Utente]]" nella parte superiore della pagina. Come programmatore non sai o ti preoccupi di come lo scriveranno i ragazzi dell'interfaccia utente: sai solo che il nome di un utente verrà mostrato da qualche parte in un messaggio.

Quindi puoi incorporare il messaggio nel tuo codice senza preoccuparti di cosa sia effettivamente quel messaggio.

File Lang (EN_US):

...
$lang['welcome_message'] = 'Welcome back %s';
...

Quindi puoi supportare qualsiasi tipo di messaggio in qualsiasi lingua usando questo nel tuo vero codice php.

sprintf($lang['welcome_message'], $user->name())

Non mi sono mai dovuto preoccupare di creare file in lingua ma questo mi sembra uno degli usi più utili
JasonDavis,

Anche questo esempio ha perfettamente senso per me dal momento che non ho fatto molte applicazioni multang.
MKN Web Solutions,

9

perché vorresti usarlo?

Si rivela molto utile quando si utilizza una sorgente (esterna) per le stringhe di lingua. Se hai bisogno di un numero fisso di variabili in una determinata stringa multilingue, devi solo conoscere l'ordinamento corretto:

EN.txt

not_found    = "%s could not be found."
bad_argument = "Bad arguments for function %s."
bad_arg_no   = "Bad argument %d for function %s."

hu.txt

not_found    = "A keresett eljárás (%s) nem található."
bad_argument = "Érvénytelen paraméterek a(z) %s eljárás hívásakor."
bad_arg_no   = "Érvénytelen %d. paraméter a(z) %s eljárás hívásakor."

Le variabili inserite non devono nemmeno essere all'inizio o alla fine in più lingue, solo le loro questioni di ordinamento.

Certo, potresti scrivere la tua funzione per eseguire questa sostituzione, senza dubbio anche con alcuni piccoli aumenti delle prestazioni, ma è molto più veloce solo (dato che hai una classe Languageper leggere le stringhe di lingua) :

/**
 * throws exception with message($name = "ExampleMethod"):
 *  - using en.txt: ExampleMethod could not be found.
 *  - using hu.txt: A keresett eljárás (ExampleMethod) nem található.
 */
throw new Exception(sprintf(Language::Get('not_found'), $name));

/**
 * throws exception with message ($param_index = 3, $name = "ExampleMethod"):
 *  - using en.txt: Bad argument 3 for function ExampleMethod.
 *  - using hu.txt: Érvénytelen 3. paraméter a(z) ExampleMethod eljárás hívásakor.
 */
throw new Exception(sprintf(Language::Get('bad_arg_no'), $param_index, $name));

Inoltre viene fornito con tutte le funzionalità di printf, quindi è anche un one-liner per la formattazione di numerosi tipi di variabili, ad esempio:


8

Come accennato, consente la formattazione dei dati di input. Ad esempio, forzare numeri 2dp, a 4 cifre, ecc. È abbastanza utile per creare stringhe di query MySQL.

Un altro vantaggio è che ti consente di separare il layout della stringa dai dati che vi vengono inseriti, quasi come inserire parametri. Ad esempio, nel caso di una query MySQL:

// For security, you MUST sanitise ALL user input first, eg:
$username = mysql_real_escape_string($_POST['username']); // etc.
// Now creating the query:
$query = sprintf("INSERT INTO `Users` SET `user`='%s',`password`='%s',`realname`='%s';", $username, $passwd_hash, $realname);

Questo metodo ha ovviamente altri usi, come ad esempio quando si stampa output come HTML, ecc.

Modifica: per motivi di sicurezza , quando si utilizza una tecnica come sopra è necessario disinfettare tutte le variabili di input con mysql_real_escape_string()prima di utilizzare questo metodo , per prevenire attacchi di inserzione di MySQL. Se analizzi input non autorizzati, il tuo sito e il tuo server verranno hackerati . (Ad eccezione, ovviamente, delle variabili che sono state completamente costruite dal tuo codice e che sono garantite per essere sicure.)


2
Tale codice è vulnerabile all'iniezione SQL. Usa segnaposto, non interpolazione query!
duskwuff -inattivo-

@duskwuff - Usato così com'è, hai ragione. Scusa, ho modificato la mia risposta.
Samuel Jaeschke,

7

L'uso di sprintf () è molto più pulito e sicuro per formattare la stringa.

Ad esempio, quando hai a che fare con variabili di input, previene sorprese inattese specificando in anticipo il formato previsto (ad esempio, che ti aspetti la stringa [ %s] o il numero [ %d]). Questo potrebbe potenzialmente aiutare con il possibile rischio di iniezione SQL , ma non impedirà se la stringa è composta da virgolette.

Aiuta anche a gestire i float, puoi specificare esplicitamente la precisione delle cifre (ad es. %.2f) Che ti salva dall'uso delle funzioni di conversione.

L'altro vantaggio è che la maggior parte dei principali linguaggi di programmazione ne ha una propria implementazione sprintf(), quindi una volta acquisita familiarità con esso, è ancora più facile da usare, piuttosto che imparare un nuovo linguaggio (come come concatenare stringhe o convertire i float).

In breve, è una buona pratica usare per avere un codice più pulito e più leggibile.

Ad esempio, vedi l' esempio reale di seguito :

$insert .= "('".$tr[0]."','".$tr[0]."','".$tr[0]."','".$tr[0]."'),";

O qualche semplice esempio che stampa ad esempio '1','2','3','4':

print "foo: '" . $a . "','" . $b . "'; bar: '" . $c . "','" . $d . "'" . "\n";

e stampa con stringa formattata:

printf("foo: '%d','%d'; bar: '%d','%d'\n", $a, $b, $c, $d);

dove printf()equivale a sprintf(), ma genera una stringa formattata invece di restituirla (alla variabile).

Qual è più leggibile?


1
Non sono in disaccordo, ma vale anche la pena ricordare che l'ho chiesto 6-7 anni fa e ripensandoci non riesco a ricordare una volta che l'ho usato da allora! Spero di trovare un posto un giorno e credo che abbia un posto ma divertente pensare di non averlo usato da quando ho fatto questa domanda che molti anni fa!
JasonDavis,

Posso dire che è in qualche modo simile all'impostazione delle variabili per DOP in PHP. Anche se vuoi dargli l'argomento di leggibilità, in quel caso preferisco usare sprintf()spezzato in più righe in cui la stringa con segnaposto è su 1 riga e i valori sono su una riga o anche più righe sottostanti, tutte rientrate correttamente di corso. Usando la tua demo nel modo che ho descritto ... i.imgur.com/DFi3ur8.png
JasonDavis

Le dichiarazioni preparate insieme alle procedure memorizzate sono il modo migliore per prevenire l'iniezione sql, non lo sprintf. Puoi ancora facilmente iniettare sql usando sprintf, se la stringa contiene una sola virgoletta
HumbleWebDev

4

Anche se ho pensato la stessa cosa, a meno che non l'abbia usata di recente. Quando si generano documenti basati sugli input dell'utente, questo sarà utile.

"<p>Some big paragraph ".$a["name"]." again have tot ake care of space and stuff .". $a["age"]. "also would be hard to keep track of punctuations and stuff in a really ".$a["token"]. paragarapoh.";

Che può essere facilmente scritto come

sprintf("Some big paragraph %s. Again have to take care of space and stuff.%s also wouldnt be hard to keep track of punctuations and stuff in a really %s paragraph",$a,$b,$c);

Oppure si può fare questo: "<p>Some big paragraph {$a['name']} more words {$a['age']}</p>". TUTTAVIA, NON DIMENTICARE di disinfettare l'input dell'utente o di aprire il codice fino a vulnerabilità XSS.
terzo

Puoi anche usare la sintassi HEREDOC . A mio avviso, entrambi sono più facili da leggere rispetto alla sintassi sprintf.
terzo

4

Questo:

"<p>Some big paragraph ".$a["name"]." again have to take care of space and stuff .". $a["age"]. "also would be hard to keep track of punctuations and stuff in a really ".$a["token"]. paragraph.";

Potrebbe anche essere scritto:

"<p>Some big paragraph {$a['name']} again have to take care of space and stuff .{$a['age']} also would be hard to keep track of punctuations and stuff in a really {$a['token']} paragraph.";

A mio avviso, è più chiaro da leggere, ma posso vedere l'uso per la localizzazione o la formattazione.


3

Alcuni dei casi tipici sono quelli in cui è necessario un controllo più preciso sul formato di output. Può essere difficile, ad esempio, assicurarsi che un valore specifico abbia una quantità specifica di spazi riempiti in primo piano, a seconda della sua lunghezza, o che un numero sia emesso in un formato preciso specifico.

Ci sono molti esempi nel manuale di PHP

Anche ciò che viene dal tuo esempio di "più facile da scrivere" .. Mentre l'eco può essere più facile da scrivere, lo sprintf è più facile da leggere, soprattutto se hai molte variabili.

Un altro motivo per utilizzare sprintf o printf potrebbe essere che si desidera consentire a un utente di definire il formato di output di un certo valore: è possibile consentire in modo sicuro che definiscano un formato di output compatibile con sprintf.

Oh, e il tuo esempio è in realtà sbagliato per una parte. sprintfrestituisce la stringa, ma echonon lo fa: la echorestituisce immediatamente e non restituisce nulla, mentre la sprintfrestituisce.


3
  1. Se hai usato C / C ++, allora saresti abituato alla funzione sprintf.

  2. Vi sono buone probabilità che la seconda riga sia meno efficiente. Eco è progettato come comando di output, mentre sprintf è progettato per sostituire i token di stringa. Non sono una persona PHP, ma sospetto che ci siano più oggetti coinvolti nell'eco. Se si comporta come farebbe Java, crea una nuova stringa ogni volta che qualcosa viene aggiunto all'elenco, quindi si finirebbe con 4 stringhe create.


Le recenti edizioni di Java convertiranno la concatenazione di stringhe in StringBuilder dietro le quinte.
RodeoClown,

1
Le stringhe in PHP non sono oggetti. Il secondo esempio usa un costrutto di linguaggio invece di una chiamata di funzione, quindi sarà impercettibilmente più veloce.
Tamlyn,

3

A volte ho qualcosa del genere, che considero un po 'più facile da leggere:

$fileName = sprintf('thumb_%s.%s', 
                    $fileId,
                    $fileInfo['extension']);

3

Di solito uso sprintf per assicurarmi che un ID proveniente dall'input dell'utente sia un numero intero, ad esempio:

// is better use prepared statements, but this is practical sometimes
$query = sprintf("SELECT * from articles where id = %d;",$_GET['article_id']);

Inoltre è usato per fare template rudimentali (per mail html o altre cose), quindi puoi riutilizzare il template in molti posti:

$mail_body = "Hello %s, ...";
$oneMail = sprintf($mail_body, "Victor");
$anotherMail = sprintf($mail_body, "Juan");

È molto utile anche per formattare i numeri in diverse rappresentazioni (ottale, controllare il decimale, ecc.).


Non è più semplice usare intval ($ _ GET ["article_id"])? Bene, in realtà ci è voluto più tempo per scrivere ... * annota il tuo metodo "Dag nabbit.
user97410

Per questo tipo di codice, utilizzare meglio mysql_real_escape_string (): $ query = sprintf ("SELECT * dagli articoli in cui id =% d;", ​​mysql_real_escape_string ($ _ GET ['article_id']));
bruno.braga,

3
define('TEXT_MESSAGE', 'The variable "%s" is in the middle!');

sprintf(TEXT_MESSAGE, "Var1");
sprintf(TEXT_MESSAGE, "Var2");
sprintf(TEXT_MESSAGE, "Var3");

3

sprintf è particolarmente utile durante la formattazione di stringhe che utilizzano numeri. Per esempio,

$oranges = -2.34;
echo sprintf("There are %d oranges in the basket", $oranges);

Output: There are -2 oranges in the basket

Le arance sono formattate come un numero intero (-2), ma andranno a capo a numeri positivi se si utilizza% u per valori senza segno. Per evitare questo comportamento, uso la funzione assoluta, abs (), per arrotondare il numero verso zero come segue:

$oranges = -5.67;
echo sprintf("There are %d oranges in the basket", abs($oranges));

Output: There are 5 oranges in the basket

Il risultato finale è un'affermazione con alta leggibilità, costruzione logica, formattazione chiara e flessibilità per l'aggiunta di ulteriori variabili come richiesto. Man mano che il numero di variabili aumenta in combinazione con funzioni che manipolano queste variabili, i vantaggi diventano più evidenti. Come ultimo esempio:

$oranges = -3.14;
$apples = 1.5;
echo sprintf("There are %d oranges and %d apples", abs($oranges), abs($apples));

Output: There are 3 oranges and 4 apples

Il lato sinistro dell'istruzione sprintf esprime chiaramente la stringa e i tipi di valori previsti, mentre il lato destro ha espresso chiaramente le variabili utilizzate e il modo in cui vengono manipolate.


Stavo per votare la tua risposta per la sua prima frase eccellente ( "sprintf è particolarmente utile quando si formattano stringhe che usano numeri" ), che è davvero il punto più importante di sprintfPHP, ma poi vedendo quegli esempi contorti che creano frutti da "mancanti" frutti :), ognuno dei quali mostra solo ripetutamente %d(e abs(), il che è irrilevante per l'argomento), invece di mostrare alcune delle numerose opzioni di formattazione dei numeri (che sarebbero rilevanti), ho cambiato idea. Ma se aggiorni la risposta, avrò comunque il mio voto in frigo per te. :) Grazie, evviva!
Sz.

3

Bene, sprintf ha molte capacità come sappiamo un esempio come di seguito:

Pochi mesi fa avevo bisogno di convertire i secondi in ore: minuti: secondi formato Come se $t = 494050 //secondsvolessi stampare come 137 h 14 m 10 scosì ho pensato alla funzione php springf()Ho solo tenuto i secondi $te echo sprintf("%02d h %s%02d m %s%02d s", floor($t/3600), $f, ($t/60)%60, $f, $t%60);mi dà137 h 14 m 10 s

La funzione sprintf () è molto utile se sappiamo come usarla.


2

L'argomento è lo stesso per l'utilizzo dei modelli. Ti consigliamo di separare Textsleev dai valori delle variabili effettive. Oltre ai poteri aggiuntivi di sprintf di cui abbiamo parlato, è solo una cosa di stile.


2

Un ottimo caso d'uso per l'utilizzo di sprintf è l'output di formati di numeri imbottiti e anche, quando si mescolano tipi diversi in una stringa. In molti casi può essere più facile da leggere e rende super semplice stampare diverse rappresentazioni della stessa variabile, specialmente quelle numeriche.


2

L'uso della funzione sprintf () sulla normale concatenazione ha il vantaggio di poter applicare diversi tipi di formattazione sulle variabili da concatenare.

Nel tuo caso, hai

$output = sprintf("Here is the result: %s for this date %s", $result, $date);

e

$output = 'Here is the result: ' .$result. ' for this date ' .$date;

Prendiamo $result = 'passed'; date = '23rd';

Utilizzando la normale concatenazione è possibile ottenere solo l'output:

Here is the result: passed for this date 23rd

Tuttavia, se si utilizza sprintf()è possibile ottenere un output modificato come:

$output = sprintf('Here is the result: %.4s for this date %.2s',$result,$date);
echo $output;

Produzione:

Here is the result: pass for this date 23

2

sprintf()è abbastanza simile a printf(). Se sai printf()nei dettagli, allora sprintf()e anchevsprintf() non è davvero difficile da capire.

una delle cose che differisce sprintf()da printf()è che sarà necessario dichiarare una variabile per catturare l'uscita dalla funzione in quanto non viene stampato direttamente / echo nulla. Vediamo i seguenti frammenti di codice:

printf("Hello %s", "world"); // "Hello world"

sprintf("Hello %s", "world"); // does not display anything

echo sprintf("Hello %s", "world"); // "Hello world"

$a = sprintf("Hello %s", "world"); // does not display anything

echo $a;// "Hello world"

Spero che aiuti.



0

Devi fare attenzione quando usi sprintf nei loop:

$a = 'Anton';
$b = 'Bert';
$c = 'Corni';
$d = 'Dora';
$e = 'Emiel';
$f = 'Falk';
$loops = 10000000;

$time = microtime(true);

for ($i = 0; $i < $loops; $i++)
{
    $test = $a . $b . $c . $d . $e . $f;
}

$concatTime = microtime(true) - $time;

$time = microtime(true);

for ($i = 0; $i < $loops; $i++)
{
    $test = "$a $b $c $d $e $f";
}

$concat2Time = microtime(true) - $time;

$time = microtime(true);

for ($i = 0; $i < $loops; $i++)
{
    $test = sprintf('%s %s %s %s %s %s', $a, $b, $c, $d, $e, $f);
}

$sprintfTime = microtime(true) - $time;

echo 'Loops: ' . $loops . '<br>';
echo '\'$a . $b . $c . $d . $e . $f\'' . ' needs ' . $concatTime  . 's<br>';
echo '"$a $b $c $d $e $f"' . ' needs ' . $concat2Time  . 's<br>';
echo 'sprintf(\'%s %s %s %s %s %s\', $a, $b, $c, $d, $e, $f)' . ' needs ' . $sprintfTime  . 's<br>';

Il che porta ai seguenti tempi (sul mio computer locale con PHP 7.2):

Anelli: 10000000

'$ a. $ b. $ c. $ d. $ e. $ f 'ha bisogno di 1.4507689476013s

"$ a $ b $ c $ d $ e $ f" ha bisogno di 1.9958319664001s

sprintf ('% s% s% s% s% s% s', $ a, $ b, $ c, $ d, $ e, $ f) ha bisogno di 9.1771278381348s


0

Lo uso per messaggi agli utenti o altri tipi di funzionalità "carini". Ad esempio, se so che userò il nome dell'utente.

$name = 'Some dynamic name';

E avere più messaggi da utilizzare in quella situazione. (Vale a dire, bloccare o seguire un altro utente)

$messageBlock = 'You have blocked %s from accessing you.';
$messageFollow = 'Following %s is a great idea!';

Puoi creare una funzione generale che fa qualcosa per l'utente e aggiungere questa stringa, e non importa quale sia la struttura della frase dovrebbe apparire piuttosto carina. Non mi piace sempre semplicemente aggiungere stringhe insieme e usare costantemente la notazione con i punti e chiudere e riaprire le stringhe solo per far apparire bene una frase. All'inizio ero un fan come la maggior parte, ma questo sembra abbastanza utile quando è necessario manipolare più stringhe e non si desidera codificare in modo rigido il posizionamento della variabile in ogni momento.

Pensaci, cosa c'è di meglio?

return $messageOne === true ? $name.'. Please use the next example' : 'Hi '.$name.', how are you?'

O

$message = $messageOne === true ? 'Option one %s' 
: ($messageTwo === true ? 'Option Two %s maybe?' : '%s you can choose from tons of grammatical instances and not have to edit variable placement and strings');

return sprintf($message, $name);

Certo è un passo in più, ma cosa succede se i tuoi controlli condizionali fanno un sacco di altre cose funzionali, quindi le citazioni e l'aggiunta iniziano a ostacolare la codifica funzionale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.