Por que usar a função sprintf em PHP?


188

Estou tentando aprender mais sobre a função PHP sprintf (), mas o php.net não me ajudou muito, pois ainda estou confuso, por que você gostaria de usá-lo?

Dê uma olhada no meu exemplo abaixo.

Por que usar isso:

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

Quando isso faz o mesmo e é mais fácil escrever IMO:

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

Estou faltando alguma coisa aqui?


40
+1, boa pergunta. Eu mesmo raramente o uso, por isso estou interessado em ver as respostas.
zombat 6/09/09

6
Observe que seus dois exemplos não são equivalentes: o primeiro simplesmente atribui o resultado $output, enquanto o segundo echoé o mesmo.
Daniel Pryden

Eu pessoalmente o uso quando concatenar muitas coisas. Só então é que acho útil, principalmente para facilitar a leitura.
AlexMorley-Finch

Respostas:


130

sprintf possui todos os recursos de formatação do printf original, o que significa que você pode fazer muito mais do que apenas inserir valores variáveis ​​em strings.

Por exemplo, especifique o formato numérico (hexadecimal, decimal, octal), número de decimais, preenchimento e muito mais. Google para printf e você encontrará muitos exemplos. O artigo da wikipedia sobre printf deve ajudá-lo a começar.


46
Anos atrás, escrevi uma boa função para números com preenchimento zero. Usado para idades antes de perceber que eu poderia simplesmente fazersprintf('%03d', $num)
DisgruntledGoat

5
O PHP sprintf tem todos os recursos de formatação ... na verdade, está faltando um importante, %,8dpor exemplo, para obter um número inteiro de 8 dígitos e vírgulas alinhado corretamente. O uso number_formaté menos conveniente em um printfestilo.
e2-e4

3
@DisgruntledGoat Você pode quebrar essa sequência de formatação ('% 03d')? Eu acho que seria realmente útil. Obrigado.
Sr. Smee

3
Você também pode repetir e reordenar os argumentos a serem exibidos. por exemplo, sprintf('%2$s %1$s, my name is also %1$s.', 'World', 'Hello');resultando emHello World, my name is also World.
fyrye 17/05/19

77

Existem muitos casos de uso para o sprintf, mas uma maneira de usá-los é armazenando uma string como esta: 'Olá, meu nome é% s' em um banco de dados ou como uma constante em uma classe PHP. Dessa forma, quando eu quero usar essa string, posso simplesmente fazer o seguinte:

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

Essencialmente, permite uma certa separação no código. Se eu usar 'Olá, meu nome é% s' em muitos lugares do meu código, posso alterá-lo para '% s é meu nome' em um lugar e ele é atualizado automaticamente em qualquer outro lugar, sem necessidade de ir a cada instância e mover-se concatenações.


8
Este. Agora adicione argumentos e traduções numerados:]
Konerak 23/04

46

Outro uso de sprintfé em aplicativos localizados como os argumentos parasprintf não precisam estar na ordem em que aparecem na string de formato.

Exemplo:

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

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

Mas uma língua como o francês ordena as palavras de maneira diferente:

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

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

(Sim, meu francês é péssimo: eu aprendi alemão na escola!)

Na realidade, você usaria gettext para armazenar as seqüências localizadas, mas você entendeu a ideia.



37

É mais fácil de traduzir.

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

As strings de tradução (gettext) agora são:

  • Aqui está o resultado:
  • para esta data

Quando traduzido para outro idioma, pode ser impossível ou resultar em frases muito estranhas.

Agora se você tiver

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

As strings de tradução (gettext) agora são:

  • Aqui está o resultado:% s para esta data% s

O que faz muito mais sentido e é muito mais flexível para traduzir para outros idiomas


1
Eu vejo onde isso seria muito útil +1
JasonDavis 6/11/2012

6
Embora para traduções provavelmente seria melhor para especificadores posição de uso, para permitir alguma flexibilidade extra quando a tradução, ou seja: echo sprintf(_("Here is the result: %1$s for this date %2$s"), $result, $date);Isso permitiria que uma tradução para modificar a frase comoFor the date %2$s, the result is %1$s
PatrikAkerstrand

1
Embora, mesmo que não estejam presentes na string original, você pode colocá-los na tradução e eles funcionarão.
espectros

17

A melhor razão que eu descobri é que ela permite que você coloque todas as seqüências de idiomas no seu arquivo de idioma, onde as pessoas podem traduzir e ordená-las conforme necessário - mas você ainda sabe que, independentemente do formato da sequência, deseja mostrar o nome do usuário.

Por exemplo, seu site dirá "Bem-vindo de volta [[Usuário]]" na parte superior da página. Como programador, você não sabe nem se importa com o que os caras da interface do usuário escreverão isso - você apenas sabe que o nome de um usuário será mostrado em algum lugar da mensagem.

Assim, você pode incorporar a mensagem ao seu código sem se preocupar com o que realmente é essa mensagem.

Arquivo Lang (EN_US):

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

Então você pode suportar qualquer tipo de mensagem em qualquer idioma usando isso no seu código php real.

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

Eu nunca tive que me preocupar em criar arquivos de idioma, mas esse parece ser um dos usos mais úteis para mim
#

Este exemplo também fez todo o sentido para mim, pois não fiz muitos aplicativos com vários idiomas.
MKN Web Solutions

9

por que você iria querer usá-lo?

Isso é muito útil ao usar uma fonte (externa) para seqüências de caracteres de idioma. Se você precisar de um número fixo de variáveis ​​em uma determinada sequência multilíngue, precisará conhecer apenas a ordem correta:

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."

As variáveis ​​inseridas nem precisam estar no início ou no fim em vários idiomas, apenas os pedidos são importantes.

Obviamente, você pode escrever sua própria função para executar essa substituição, sem dúvida, mesmo com alguns pequenos aumentos de desempenho, mas é muito mais rápido do que isso (desde que você tenha uma classe Languagepara ler as strings de idiomas) :

/**
 * 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));

Ele também vem com todos os recursos de printf, portanto, é também uma linha para formatar vários tipos de variáveis, por exemplo:


8

Como mencionado, ele permite a formatação dos dados de entrada. Por exemplo, forçar números 2dp, 4 dígitos, etc. É bastante útil para criar strings de consulta do MySQL.

Outra vantagem é que ele permite que você separe o layout da string dos dados que estão sendo alimentados, quase como alimentar os parâmetros. Por exemplo, no caso de uma consulta 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);

É claro que esse método tem outros usos, como na impressão de saída como HTML, etc.

Edit: Por razões de segurança , ao usar uma técnica como acima, você deve limpar todas as variáveis ​​de entrada mysql_real_escape_string()antes de usar este método , para evitar ataques de inserção do MySQL. Se você analisar entradas não autorizadas, seu site e servidor serão invadidos . (Com exceção de, é claro, variáveis ​​que foram completamente construídas pelo seu código e são garantidas como seguras.)


2
Esse código é vulnerável à injeção de SQL. Use espaços reservados, não interpolação de consulta!
duskwuff -inactive-

@duskwuff - Usado como está, você está certo. Desculpe, eu alterei minha resposta.
Samuel Jaeschke

7

Usando sprintf () é muito mais limpo e seguro para formatar sua string.

Por exemplo, quando você lida com variáveis ​​de entrada, evita surpresas inesperadas especificando o formato esperado com antecedência (por exemplo, que você está esperando a string [ %s] ou o número [ %d]). Isso pode potencialmente ajudar com o possível risco de injeção de SQL , mas não impedirá que a string contenha aspas.

Também ajuda a lidar com carros alegóricos, você pode especificar explicitamente a precisão do dígito (por exemplo, %.2f ) que evita o uso de funções de conversão.

As outras vantagens são que a maioria das principais linguagens de programação possui sua própria implementação de sprintf() . Assim, quando você se familiarizar com ela, fica ainda mais fácil usar, em vez de aprender uma nova linguagem (como concatenar seqüências de caracteres ou converter floats).

Em resumo, é uma boa prática usar para ter um código mais limpo e legível.

Por exemplo, veja o exemplo real abaixo :

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

Ou algum exemplo simples que imprime, por exemplo '1','2','3','4':

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

e impressão com sequência formatada:

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

onde printf()é equivalente sprintf(), mas gera uma sequência de caracteres formatada em vez de retorná-la (para a variável).

Qual é mais legível?


1
Não discordo, mas também vale a pena mencionar que perguntei isso há 6 a 7 anos e, pensando bem, não me lembro uma vez que usei isso desde então! Espero encontrar um lugar para isso algum dia e acredito que tenha um lugar, mas engraçado pensar que não o usei desde que fiz essa pergunta há muitos anos!
23415 JasonDavis

Posso dizer que é um pouco semelhante à configuração de variáveis ​​para DOP em PHP. Além disso, se você quiser fornecer o argumento de legibilidade, nesse caso, eu prefiro usar sprintf()quebra em várias linhas, onde a string com espaços reservados está em 1 linha e os valores estão em uma linha ou até várias linhas abaixo dela, todos recuados corretamente de curso. Usando sua demo da maneira que descrevi ... i.imgur.com/DFi3ur8.png
JasonDavis

Instruções preparadas em conjunto com procedimentos armazenados são a melhor maneira de impedir a injeção de sql, não o sprintf. Você pode ainda facilmente sql injetar usando sprintf, se a cadeia acontece para conter uma única citação
HumbleWebDev

4

Mesmo eu pensei a mesma coisa, a menos que eu o usei recentemente. Quando você gera documentos com base nas entradas do usuário, isso será útil.

"<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.";

O que pode ser facilmente escrito como

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);

Ou você pode fazer isso: "<p>Some big paragraph {$a['name']} more words {$a['age']}</p>". NO ENTANTO, NÃO SE ESQUEÇA de higienizar a entrada do usuário ou você abre seu código com vulnerabilidades XSS.
Terceira-

Você também pode usar a sintaxe HEREDOC . Na minha opinião, ambos são mais fáceis de ler do que a sintaxe sprintf.
Terceira-

4

Este:

"<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.";

Também pode ser escrito:

"<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.";

Na minha opinião, isso é mais claro de ler, mas posso ver o uso para localizar ou formatar.


3

Alguns casos típicos são onde você precisa de um controle mais preciso sobre o formato de saída. Pode ser complicado, por exemplo, garantir que um valor específico tenha uma quantidade específica de espaços preenchidos para a frente, dependendo do comprimento, ou que um número seja emitido em um formato preciso específico.

Existem muitos exemplos no manual do PHP

Além disso, o que vem ao seu exemplo de "mais fácil de escrever". Embora o eco possa ser mais fácil de escrever, o sprintf é mais fácil de ler, especialmente se você tiver muitas variáveis.

Outro motivo para usar o sprintf ou printf pode ser que você queira permitir que um usuário defina o formato de saída de algum valor - você pode com segurança permitir que ele defina um formato de saída compatível com o sprintf.

Ah, e seu exemplo está realmente errado em uma parte. sprintfretorna a string, mas echonão - echoimediatamente a produz e não retorna nada, enquanto sprintfapenas a retorna.


3
  1. Se você usou o C / C ++, estaria acostumado à função sprintf.

  2. Há uma boa chance de que a segunda linha seja menos eficiente. O eco é projetado como um comando de saída, enquanto o sprintf é projetado para fazer a substituição do token de cadeia. Eu não sou uma pessoa PHP, mas suspeito que haja mais objetos envolvidos com o eco. Se ele agir como o Java, criará uma nova string sempre que algo for adicionado à lista, para que você acabe com 4 strings criadas.


Edições recentes do Java converterão a concatenação de String em um StringBuilder nos bastidores.
RodeoClown 6/09/09

1
Strings no PHP não são objetos. O segundo exemplo usa uma construção de linguagem em vez de uma chamada de função, por isso será imperceptivelmente mais rápido.
Tamlyn

3

Às vezes, tenho algo assim, que considero um pouco mais fácil de ler:

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

3

Normalmente, uso o sprintf para garantir que um ID proveniente da entrada do usuário seja um número inteiro, por exemplo:

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

Também é usado para criar modelos rudimentares (para emails html ou outras coisas), para que você possa reutilizar o modelo em muitos lugares:

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

Também é muito útil formatar números em diferentes representações (octal, controlar a casa decimal, etc.).


Não é mais fácil usar intval ($ _ GET ["article_id"])? Bem, na verdade, levou mais de digitação ... * notas abaixo seu método de" Dag nabbit.
user97410

Para esse tipo de código, use melhor o mysql_real_escape_string (): $ query = sprintf ("SELECT * de artigos em que id =% d;", ​​mysql_real_escape_string ($ _ GET ['article_id']));
Bruno.braga 19/01/12

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

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

3

O sprintf é particularmente útil ao formatar strings que usam números. Por exemplo,

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

Output: There are -2 oranges in the basket

As laranjas são formatadas como um número inteiro (-2), mas serão agrupadas em números positivos se alguém usar% u para valores não assinados. Para evitar esse comportamento, eu uso a função absoluta, abs (), para arredondar o número para zero da seguinte maneira:

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

Output: There are 5 oranges in the basket

O resultado final é uma declaração com alta legibilidade, construção lógica, formatação clara e flexibilidade para adicionar variáveis ​​adicionais conforme necessário. À medida que o número de variáveis ​​aumenta em combinação com as funções que manipulam essas variáveis, os benefícios se tornam mais aparentes. Como exemplo final:

$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

O lado esquerdo da instrução sprintf expressa claramente a sequência e os tipos de valores esperados, enquanto o lado direito expressa claramente as variáveis ​​usadas e como elas estão sendo manipuladas.


Eu estava prestes a votar sua resposta por sua excelente primeira frase ( "sprintf é particularmente útil ao formatar strings que usam números" ), que é realmente o ponto mais importante do sprintfPHP, mas depois vejo esses exemplos complicados criando frutos de "falta" frutas :), cada uma mostrando apenas repetidamente %d(e abs(), o que é irrelevante para o tópico), em vez de mostrar algumas das inúmeras opções de formatação de números (que seriam relevantes), mudei de idéia. Mas se você atualizar a resposta, ainda terei meu voto positivo na geladeira para você. :) Thx, felicidades!
Sz.

3

Bem, sprintf tem muitos recursos, como conhecemos um exemplo abaixo:

Poucos meses atrás, eu estava precisando converter segundos para horas: formato de minuto: segundos Como $t = 494050 //secondseu queria imprimir assim, 137 h 14 m 10 sentão eu vim com a função php springf()Eu apenas segurei os segundos $te echo sprintf("%02d h %s%02d m %s%02d s", floor($t/3600), $f, ($t/60)%60, $f, $t%60);me dei137 h 14 m 10 s

A função sprintf () é muito útil se soubermos usá-la.


2

O argumento é o mesmo para usar modelos. Você deseja separar seu Textsleev dos valores reais das variáveis. Além dos poderes adicionais do sprintf mencionados, é apenas uma coisa de estilo.


2

Um bom caso de uso para o uso do sprintf é a saída de formatos de números preenchidos e também, ao misturar tipos diferentes em uma sequência. Pode ser mais fácil de ler em muitos casos e torna super simples imprimir diferentes representações da mesma variável, especialmente as numéricas.


2

O uso da função sprintf () sobre a concatenação comum tem a vantagem de poder aplicar diferentes tipos de formatação nas variáveis ​​a serem concatenadas.

No seu caso, você tem

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

e

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

Vamos dar $result = 'passed'; date = '23rd';

Usando concatenação comum, você pode obter apenas a saída:

Here is the result: passed for this date 23rd

No entanto, se você usar, sprintf()poderá obter uma saída modificada, como:

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

Resultado:

Here is the result: pass for this date 23

2

sprintf()é bem parecido com printf(). Se você souber printf()em detalhes então sprintf()e atévsprintf() é realmente difícil de entender.

uma das coisas que difere sprintf()de printf()é que você vai precisar declarar uma variável para pegar a saída da função, pois não imprimir diretamente / echo nada. Vamos ver os seguintes trechos de código:

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"

Espero que ajude.



0

Você precisa ter cuidado ao usar o sprintf em loops:

$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>';

O que leva aos seguintes horários (na minha máquina local com PHP 7.2):

Loops: 10000000

'$ a. $ b. $ c. $ d. $ e. $ f 'precisa de 1.4507689476013s

"$ a $ b $ c $ d $ e $ f" precisa de 1.9958319664001s

sprintf ('% s% s% s% s% s% s', $ a, $ b, $ c, $ d, $ e, $ f) precisa 9.1771278381348s


0

Eu o uso para mensagens para usuários ou outros tipos "bonitos" de funcionalidade. Por exemplo, se eu sei que vou usar o nome do usuário.

$name = 'Some dynamic name';

E tem várias mensagens para usar nessa situação. (Ou seja, bloqueando ou seguindo outro usuário)

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

Você pode criar uma função geral que faça algo com o usuário e adicionar essa string, e não importa qual seja a estrutura da frase, ela parecerá bastante agradável. Eu sempre não gosto de anexar seqüências de caracteres juntas e constantemente usar notação de ponto e fechar e reabrir seqüências apenas para fazer uma frase parecer boa. Eu era um fã no começo, como a maioria, mas isso parece bastante útil quando várias seqüências precisam ser manipuladas e você não deseja codificar permanentemente o posicionamento da variável.

Pense nisso, o que parece melhor?

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

Ou

$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);

Claro que é uma etapa extra, mas e se suas verificações condicionais fizerem um monte de outras coisas funcionais, as citações e os anexos começarão a atrapalhar a codificação funcional.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.