What’s the difference in using sprintf in relation to using variables within the string?

Asked

Viewed 366 times

6

Seeing some libraries and examples is common find the sprintf in some situations where I find it strange.

Reading your documentation I noticed that there are several types of formatting, however I see some cases that I don’t see the use of this, since it only inserts a variable in a string.

A real example, extracted from Statuspage.io:

$ch = curl_init(sprintf("%s/pages/%s/metrics/%s/data.json", $BASE_URI, $PAGE_ID, $METRIC_ID));

An additional example, taken from Yubico/Yubikey:

$query = sprintf("SELECT username FROM demoserver WHERE id='%s'",
           pg_escape_string($identity));

What is different from strintf against this:

$ch = curl_init("$BASE_URI/pages/$PAGE_ID/metrics/$METRIC_ID/data.json");

$query = 'SELECT username FROM demoserver WHERE id="'.pg_escape_string($identity).'"';

What would be the advantage of using the sprintf in situations like this?

  • I see no advantage in situations like this, I think it’s nice to use when the argument of sprintf is an argument of a function. You have to balance to see what is necessary, and what is foreign

  • Hey, do you think you can score one of the answers?

4 answers

6


The function sprintf() format a string based on the order of the parameters defined in the first argument, which makes everything very dynamic, allowing you to format strings very flexibly.

An example of great utility is when you need to write data in different languages.

Formatting for templates, data output, etc.

Common cases are names of persons, personal treatment pronouns, addresses, etc.

The example below clarifies better:

// Define idioma. Modifique para "pt" e veja como é a saída dos dados.
$l = 'ja';

// tratamento pessoal
$t['ja'] = '様';
// nome da pessoa
$n['ja'] = array('name' => '太郎', 'surname' => '山田');
// endereço
$a['ja'] = array(
    'postal_code' => '104-0045',
    'country_name' => '日本',
    'province_name' => '東京都',
    'city_name' => '東京',
    'city_subregion' => '中央区',
    'county_name' => '明石町',
    'building' => 'マンション名123'
);

// tratamento pessoal
$t['pt'] = 'Sr(a)';
// nome da pessoa
$n['pt'] = array('name' => 'Fulano', 'surname' => 'Silva');
// endereço
$a['pt'] = array(
    'postal_code' => '06453-040',
    'country_name' => 'Brasil',
    'province_name' => 'SP',
    'city_name' => 'Barueri',
    'city_subregion' => '',
    'county_name' => 'Alphaville',
    'building' => 'Calçadas das Papoulas 123'
);

// regra de formatação para idioma japonês
$nf['ja'] = '%3$s %2$s %1$s'; // nome
$af['ja'] = '〒%1$s %2$s %3$s %4$s %5$s %6$s %7$s'; // endereço

// regra de formatação para idioma português
$nf['pt'] = '%1$s %2$s %3$s'; // nome
$af['pt'] = '%7$s %6$s'.(empty($a[$l]['city_subregion'])? '': '- %5$s').', %4$s - %3$s, %1$s, %2$s'; // endereço

// escreve o nome
echo sprintf($nf[$l], $t[$l], $n[$l]['name'], $n[$l]['surname']).'<br>';
// escreve o endereço
echo sprintf(
    $af[$l],
    $a[$l]['postal_code'],
    $a[$l]['country_name'],
    $a[$l]['province_name'],
    $a[$l]['city_name'],
    $a[$l]['city_subregion'],
    $a[$l]['county_name'],
    $a[$l]['building']
);

Note that at the time of writing, nothing changes. The structure of the data in the arrays also does not change. Both are equal. What makes the difference is the formatting rule, which informs the function sprintf() how and where to concatenate the other parameters.

Try to get the same result without using the function. It becomes complicated with many conditionals in a tangle of codes. A nightmare.

This is an example only for 2 languages and is a very simple and "easy" case. There are more complex things, however, the above example is enough to ask the question.

Number formatting

There are several other uses of the function, such as converting a number in scientific notation format to decimal/float.

$n = '5.3882598876953E-5';

// Esse trecho é para obter o exponente. Não é relevante para a questão
if ($p = strpos($n, '-')) {
    $decimals = strlen(substr($n, 0, $p - 1));
    $exponent = substr($n, $p + 1);
    $decimals += !empty($exponent)?$exponent - 1: 0;
} else {
    $decimals = strlen(substr($n, strpos($n, '.') + 1));
}

echo $n.'<br>'.sprintf('%.'.$decimals.'f', 1 * $n);

Imagine doing it without the function sprintf().

Opinion

Finally, personal opinion, but without wishing to belittle anyone, I find it unnecessary to use it at all just to make the code beautiful. It makes no sense to use in cases where the format is static, for example. It would just be consuming unnecessary processes.

Example of situation where it is done unnecessary

$ch = curl_init(sprintf("%s/pages/%s/metrics/%s/data.json", $BASE_URI, $PAGE_ID, $METRIC_ID));

It makes no difference if you make an organized, standardized concatenation.

$ch = curl_init($BASE_URI.'/pages/'.$PAGE_ID.'/metrics/'.$METRIC_ID'./data.json');

As mentioned above, the format in this case is static. There is no need to use a dynamic formatting feature for something static.

$var1 = 'A';
$var2 = 'B';
$var3 = 'C';
echo $var1.''.$var2.''.$var3;
//Tempo: 596μs e algumas vezes a 610μs
// Não faz menor diferença usar vírgula ou ponto para concatenar.

$var1 = 'A';
$var2 = 'B';
$var3 = 'C';
echo sprintf('%1$s %2$s %3$s', $var1, $var2, $var3);
//Tempo: 786μs, porém, fica "flutuando" entre 880μs e 900μs

μs: microseconds

The difference for a single, simple line is 2 to 3 microseconds. Of course for a single execution it is irrelevant, however, if the application adopts the function to make all concatenations, add them. If you have 100 concatenations in the codes, it is no longer irrelevant. A loss of performance for an unnecessary "whim".





The examples have didactic purpose. They are merely illustrative.

5

The sprintf in PHP has basically the same function as in C, which is to allow the value formatting resources available in printf can be applied to a string, instead of playing in the terminal.

I agree, the example you gave does not illustrate a case where the sprintf is really useful. However, in my opinion, the code has become cleaner.

But here’s a case where he can assist.

$pi = 3.14159265359;
$piResumido = sprintf("PI com duas casas decimais: %.2f",$pi);
echo $piResumido;

3

Keep in mind that function sprintf can do much more than simply reserve a space to be filled with an argument.

It is much more comprehensive than that. Through this function, you can format numbers with zero fills on the left, you can process integers and floats.

Example:

sprintf('%010.2f', 11.66); // '0000011.66'
sprintf('%010d', 11.66); // '0000000011'

That is, the argument can be processed in several ways.

It is worth remembering that, between the call of a function and a statement of a string, the second case would be more performatic.

I am not here to preach microtimization (even because I hate it), but I believe that in the example described in the question there is no real benefit in using sprintf, although I have to confess who in some cases (as in the elaboration of a file path, which is a process that should be careful) I use sprintf for organization purposes, no matter to me the performance, since the performance does not depend on a function only, but on the whole work.

I’m not saying prioritize readability or performance, but be moderate between the two, because everything in this life without balance creates problems.

2

Visibility

sprintf can facilitate understanding and improve visibility of a code snippet, take into account the examples below with small variables:

// exemplo 1
$ch = curl_init(sprintf("%s/pages/%s/metrics/%s/data.json", $BASE_URI, $PAGE_ID, $METRIC_ID));

// exemplo 2
$ch = curl_init("$BASE_URI/pages/$PAGE_ID/metrics/$METRIC_ID/data.json");

// exemplo 3
$ch = curl_init("{$BASE_URI}/pages/{$PAGE_ID}/metrics/{$METRIC_ID}/data.json");

// exemplo 4
$ch = curl_init($BASE_URI.'/pages/'.$PAGE_ID.'/metrics/'.$METRIC_ID.'/data.json');

Everyone was easy to understand, there was not much difference, although I prefer example 1 and 3.

But now look at this other scenario with "big" variables, it is even clearer that the use of sprintf improves visibility.
Compare the ugly example with the beautiful one and realize that it is much easier to understand in the beautiful set of information that the string wants to pass.

// feio
// Quebrei em linhas para ficar "menos pior"
$description  = "Ação: {$acao->getDescricao()} (ID: {$acao->getDescricao()}), ";
$description .= "Pessoa: {$pessoa->getDescricao()} (ID: {$pessoa->getId()}), ";
$description .= "Local: {$loja->getDescricao()} (ID: {$loja->getId()}), ";
$description .= "Data: {$data->format('d/m/Y')}";

// bonito
$description .= sprintf('Ação: %s (ID: %d), Pessoa: %s (ID: %d), Local: %s (ID: %d), Data: %s',
    $acao->getDescricao(),
    $acao->getId(),
    $pessoa->getDescricao(),
    $pessoa->getId(),
    $loja->getDescricao(),
    $loja->getId(),
    $data->format('d/m/Y')
);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.