Зачем использовать функцию sprintf в PHP?


188

Я пытаюсь узнать больше о функции PHP sprintf (), но php.net не сильно мне помог, так как я все еще растерялся, зачем вам его использовать?

Посмотрите на мой пример ниже.

Зачем использовать это:

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

Когда это делает то же самое и легче написать ИМО:

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

Я что-то здесь упускаю?


40
+1, хороший вопрос. Я редко пользуюсь им сам, поэтому мне интересно посмотреть ответы.
зомбат

6
Обратите внимание, что ваши два примера не эквивалентны: первый просто присваивает результат $output, а второй - echoего.
Даниэль Приден

Я лично использую его, когда объединяю много вещей. Только тогда я нахожу это полезным, в основном для удобства чтения.
AlexMorley-Finch

Ответы:


130

sprintf имеет все возможности форматирования исходного printf, что означает, что вы можете сделать гораздо больше, чем просто вставлять значения переменных в строки.

Например, укажите формат числа (шестнадцатеричный, десятичный, восьмеричный), количество десятичных знаков, отступы и многое другое. Google для printf, и вы найдете множество примеров. Википедии статья на Printf должно вам начать работу.


46
Несколько лет назад я написал замечательную функцию для заполнения нулями чисел. Использовали целую вечность, прежде чем sprintf('%03d', $num)
поняли,

5
В PHP sprintf есть все возможности форматирования ... на самом деле отсутствует важный, %,8dнапример, чтобы получить правильно выровненное 8-значное целое число, разделенное запятыми. Использование number_formatменее удобно в printfстиле.
e2-e4

3
@DisgruntledGoat Можете ли вы разбить эту строку форматирования ('% 03d')? Я думаю, это было бы очень полезно. Спасибо.
Мистер Сми

3
Вы также можете повторить и изменить порядок аргументов для отображения. например, в sprintf('%2$s %1$s, my name is also %1$s.', 'World', 'Hello');результатеHello World, my name is also World.
фырье

77

Существует множество вариантов использования sprintf, но я использую их одним способом, сохраняя строку типа «Hello, My Name is% s» в базе данных или в качестве константы в классе PHP. Таким образом, когда я хочу использовать эту строку, я могу просто сделать это:

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

По сути, это допускает некоторое разделение в коде. Если я использую «Здравствуйте, мое имя% s» во многих местах моего кода, я могу изменить его на «% s - мое имя» в одном месте, и оно обновляется везде в другом месте автоматически, без необходимости переходить к каждому экземпляру и перемещаться конкатенации.


8
Это. Теперь добавьте пронумерованные аргументы и переводы:]
Конерак

46

Другое использование sprintfв локализованных приложениях в качестве аргументов, которые sprintfне обязательно должны быть в том порядке, в котором они появляются в строке формата.

Пример:

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

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

Но язык как французский заказывает слова по-другому:

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

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

(Да, мой французский отстой: я выучил немецкий в школе!)

В действительности вы бы использовали gettext для хранения локализованных строк, но вы поняли идею.



37

Проще перевести.

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

Строки перевода (gettext) теперь:

  • Вот результат:
  • на эту дату

При переводе на другой язык это может оказаться невозможным или привести к очень странным предложениям.

Теперь, если у вас есть

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

Перевод (gettext) строки теперь:

  • Вот результат:% s на эту дату% s

Что имеет гораздо больше смысла, и это гораздо более гибко переводить на другие языки


1
Я вижу, где это было бы очень полезно +1
JasonDavis

6
Хотя для переводов, вероятно, было бы лучше использовать спецификаторы позиции, чтобы обеспечить некоторую дополнительную гибкость при переводе, то есть: 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
PatrikAkerstrand,

1
Хотя, даже если они не присутствуют в исходной строке, вы можете поместить их в перевод, и они будут работать.
спектры

17

Лучшая причина, которую я нашел, заключается в том, что она позволяет вам поместить все языковые строки в ваш языковой файл, где люди могут переводить и упорядочивать их по мере необходимости, - но вы все равно знаете, что независимо от того, в каком формате находится строка - вы хотите показать имя пользователя.

Например, ваш сайт скажет «Добро пожаловать [[Пользователь]]» в верхней части страницы. Как программист, вы не знаете или не заботитесь о том, как парни из UI собираются это писать - вы просто знаете, что имя пользователя будет показано где-то в сообщении.

Таким образом, вы можете встроить сообщение в свой код, не беспокоясь о том, что это сообщение на самом деле.

Файл Lang (EN_US):

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

Затем вы можете поддерживать сообщения любого типа на любом языке, используя это в своем фактическом PHP-коде.

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

Мне никогда не приходилось беспокоиться о создании языковых файлов, но мне кажется, что это одно из самых полезных применений
JasonDavis

Этот пример также имел для меня смысл, так как я не делал многоязыковых приложений.
MKN Web Solutions

9

почему вы хотите его использовать?

Это оказывается очень полезным при использовании (внешнего) источника для языковых строк. Если вам нужно фиксированное количество переменных в заданной многоязычной строке, вам нужно знать только правильный порядок:

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

Вставленные переменные не обязательно должны быть в начале или в конце на нескольких языках, важен только их порядок.

Конечно, вы могли бы написать свою собственную функцию для выполнения этой замены, несомненно, даже с небольшим повышением производительности, но это гораздо быстрее (если у вас есть класс Languageдля чтения языковых строк) :

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

Он также поставляется с полным набором возможностей и printf, таким образом, является однострочным для форматирования различных типов переменных, например:


8

Как уже упоминалось, это позволяет форматировать входные данные. Например, форсирование 2dp, 4-значных чисел и т. Д. Это очень полезно для построения строк запросов MySQL.

Еще одним преимуществом является то, что он позволяет вам отделить расположение строки от данных, вводимых в нее, почти как в параметрах. Например, в случае запроса 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);

Этот метод, конечно, имеет другое применение, например, при печати вывода в формате HTML и т. Д.

Редактировать: Из соображений безопасности при использовании описанного выше метода вы должны очистить все входные переменные mysql_real_escape_string()перед использованием этого метода , чтобы предотвратить атаки вставки MySQL. Если вы проанализируете несанкционированный ввод, ваш сайт и сервер будут взломаны . (За исключением, конечно, переменных, которые были полностью созданы вашим кодом и гарантированно безопасны.)


2
Этот код уязвим для внедрения SQL. Используйте заполнители, а не интерполяцию запросов!
сумерки -неактивно-

@duskwuff - Используется как есть, вы правы. Извините, я исправил свой ответ.
Самуэль Яешке

7

Использование sprintf () намного чище и безопаснее для форматирования вашей строки.

Например, когда вы имеете дело с входными переменными, он предотвращает неожиданные неожиданности, заранее указав ожидаемый формат (например, ожидаемую строку [ %s] или число [ %d]). Это может потенциально помочь с возможным риском внедрения SQL , но не предотвратит кавычки, состоящие из строк.

Это также помогает работать с числами с плавающей запятой, вы можете явно указать точность цифр (например %.2f), которая избавляет вас от использования функций преобразования.

Другое преимущество состоит в том, что большинство основных языков программирования имеют свою собственную реализацию sprintf(), поэтому, когда вы познакомитесь с ним, его будет еще проще использовать, чем изучать новый язык (например, как объединять строки или преобразовывать числа с плавающей запятой).

Таким образом, это хорошая практика, чтобы иметь более чистый и читаемый код.

Например, посмотрите реальный пример ниже :

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

Или простой пример, который печатает, например '1','2','3','4':

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

и печать с форматированной строкой:

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

где printf()эквивалентно sprintf(), но выводит отформатированную строку вместо ее возврата (в переменную).

Что является более читабельным?


1
Я не согласен, но также стоит упомянуть, что я спрашивал об этом 6-7 лет назад и, вспоминая, не могу вспомнить, что использовал это с тех пор! Я надеюсь когда-нибудь найти место для этого и верю, что у него есть место, но забавно думать, что я не использовал его с тех пор, как задал этот вопрос много лет назад!
Джейсон Дэвис,

Я могу сказать, что это несколько похоже на установку переменных для PDO в PHP. Также, если вы хотите дать ему аргумент читабельности, то в этом случае я предпочитаю использовать sprintf()разбитый на несколько строк, где строка с заполнителями находится на 1 строке, а значения находятся на строке или даже на нескольких строках под ней, все с правильными отступами курс. Используя ваше демо так, как я описал ... i.imgur.com/DFi3ur8.png
JasonDavis

Подготовленные операторы в сочетании с хранимыми процедурами - лучший способ предотвратить внедрение SQL, а не sprintf. Вы все еще можете легко внедрить sql с помощью sprintf, если в строке содержится одна кавычка
HumbleWebDev,

4

Даже я, хотя то же самое, если я не использовал это недавно. Когда вы генерируете документы на основе пользовательского ввода, это будет удобно.

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

Что можно легко записать как

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

Или вы можете сделать это: "<p>Some big paragraph {$a['name']} more words {$a['age']}</p>". ОДНАКО, НЕ ЗАБУДЬТЕ дезинфицировать ввод пользователя, или вы открываете свой код до уязвимостей XSS.
Тридцать

Вы также можете использовать синтаксис HEREDOC . На мой взгляд, оба легче читать, чем синтаксис sprintf.
Тридцать

4

Это:

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

Также может быть написано:

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

На мой взгляд, это более понятно для чтения, но я вижу использование для локализации или форматирования.


3

В некоторых типичных случаях требуется более точный контроль над форматом вывода. Может быть сложно, например, убедиться, что конкретное значение имеет определенное количество пробелов, добавленных вперед, в зависимости от его длины, или что число выводится в определенном точном формате.

Есть много примеров в руководстве по PHP

Также то, что приходит к вашему примеру «проще писать». Хотя эхо может быть легче писать, sprintf легче читать, особенно если у вас много переменных.

Другая причина использования sprintf или printf может заключаться в том, что вы хотите позволить пользователю определять выходной формат некоторого значения - вы можете спокойно позволить ему определять совместимый с sprintf выходной формат.

Ох, и ваш пример на самом деле не так с одной стороны. sprintfвозвращает строку, а echoне - echoсразу выводит ее и ничего не возвращает, а sprintfпросто возвращает.


3
  1. Если вы использовали C / C ++, то вы бы привыкли к функции sprintf.

  2. Есть большая вероятность, что вторая линия менее эффективна. Echo разработан как выходная команда, тогда как sprintf предназначен для подстановки строковых токенов. Я не PHP человек, но я подозреваю, что с эхом связано больше объектов. Если он работает как Java, он создает новую строку каждый раз, когда что-то добавляется в список, так что вы получите 4 созданные строки.


Последние выпуски Java преобразуют конкатенацию String в StringBuilder за кулисами.
RodeoClown

1
Строки в PHP не являются объектами. Во втором примере вместо вызова функции используется языковая конструкция, поэтому она будет незаметно быстрее.
Тамлин

3

Иногда я получаю что-то вроде этого, которое я считаю немного более простым для чтения:

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

3

Я обычно использую sprintf, чтобы гарантировать, что идентификатор, полученный из пользовательского ввода, является целым числом, например:

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

Также используется для создания элементарных шаблонов (для html-писем или других вещей), так что вы можете использовать шаблон во многих местах:

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

Также очень полезно форматировать числа в разных представлениях (восьмеричное, управлять десятичным знаком и т. Д.).


Не проще ли использовать intval ($ _ GET ["article_id"])? Ну, на самом деле потребовалось больше печатать ... * записывает ваш метод "Dag Nabbit.
user97410

Для этого типа кода лучше использовать встроенную функцию mysql_real_escape_string (): $ query = sprintf («SELECT * из статей, где 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 особенно полезен при форматировании строк, использующих числа. Например,

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

Output: There are -2 oranges in the basket

Апельсины отформатированы как целое число (-2), но будут округлены до положительных чисел, если использовать% u для значений без знака. Чтобы избежать такого поведения, я использую абсолютную функцию abs (), чтобы округлить число до нуля следующим образом:

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

Output: There are 5 oranges in the basket

Конечным результатом является оператор с высокой читабельностью, логической конструкцией, четким форматированием и гибкостью для добавления дополнительных переменных по мере необходимости. Поскольку число переменных увеличивается в сочетании с функциями, которые управляют этими переменными, преимущества становятся более очевидными. В качестве последнего примера:

$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

Левая часть оператора sprintf четко отображает строку и типы ожидаемых значений, в то время как правая часть четко отображает используемые переменные и то, как они манипулируют.


Я собирался поднять ваш ответ за его превосходное первое предложение ( «sprintf особенно полезен при форматировании строк, использующих числа» ), что действительно является наиболее важным моментом sprintfв PHP, но затем я увидел, что эти замысловатые примеры создают плоды из «пропавших без вести» фрукты :), каждый из которых только показывает %dabs(), что не имеет отношения к теме), вместо того, чтобы показывать некоторые из множества вариантов форматирования чисел (которые были бы актуальны), я передумал. Но если вы обновите ответ, у меня все еще будет мой голос в холодильнике для вас. :) Спасибо, ура!
СЗ

3

Ну, sprintf есть много возможностей, как мы знаем пример ниже:

Несколько месяцев назад мне нужно было преобразовать секунды в часы: минуты: секунды. Как будто $t = 494050 //secondsя хотел напечатать 137 h 14 m 10 sтак, я придумал функцию php, springf()я просто держу секунды $tи echo sprintf("%02d h %s%02d m %s%02d s", floor($t/3600), $f, ($t/60)%60, $f, $t%60);дает мне137 h 14 m 10 s

Функция sprintf () очень полезна, если мы знаем, как ее использовать.


2

Аргумент тот же для использования шаблонов. Вы хотите отделить ваш Textsleev от фактических значений переменных. Помимо дополнительных возможностей sprintf, о которых мы упоминали, это просто стиль.


2

Действительно хорошим вариантом использования sprintf является вывод числовых форматов с добавками, а также при смешивании различных типов в строке. Во многих случаях это может быть проще для чтения и делает его очень простым для печати различных представлений одной и той же переменной, особенно числовых.


2

Использование функции sprintf () по сравнению с обычной конкатенацией имеет то преимущество, что вы можете применять различные типы форматирования к переменным, которые должны быть объединены.

В вашем случае у вас есть

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

и

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

Давайте возьмем $result = 'passed'; date = '23rd';

Используя обычную конкатенацию, вы можете получить только результат:

Here is the result: passed for this date 23rd

Однако, если вы используете, sprintf()вы можете получить модифицированный вывод, такой как:

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

Вывод:

Here is the result: pass for this date 23

2

sprintf()очень похоже на printf(). Если вы знаете printf()в деталях, то sprintf()и дажеvsprintf() и не очень трудно понять.

одна из вещей , которые отличается sprintf()от printf(), что вам нужно объявить переменную , чтобы поймать выход из функции , поскольку она не напрямую печатать / эхо ничего. Давайте посмотрим следующие фрагменты кода:

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"

Надеюсь, это поможет.



0

Вы должны быть осторожны при использовании sprintf в циклах:

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

Что приводит к следующему времени (на моей локальной машине с PHP 7.2):

Петли: 10000000

$ a. $ б. $ c. $ d. $ е. $ f 'нужно 1.4507689476013s

«$ a $ b $ c $ d $ e $ f» требует 1.9958319664001s

sprintf ('% s% s% s% s% s% s', $ a, $ b, $ c, $ d, $ e, $ f) необходимо 9.1771278381348s


0

Я использую это для сообщений пользователям или других "симпатичных" типов функциональности. Например, если я знаю, я собираюсь использовать имя пользователя.

$name = 'Some dynamic name';

И иметь несколько сообщений для использования в этой ситуации. (Т.е. блокирование или отслеживание другого пользователя)

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

Вы можете создать общую функцию, которая делает что-то для пользователя, и добавить эту строку, и независимо от того, какова структура предложения, она должна выглядеть довольно красиво. Мне всегда не нравится просто добавлять строки вместе и постоянно использовать точечную запись, а также закрывать и открывать строки, чтобы предложение выглядело хорошо. Сначала я был фанатом, как и большинство, но это кажется довольно полезным, когда нужно манипулировать несколькими строками, и вы не хотите жестко кодировать размещение переменной каждый раз.

Подумайте об этом, что выглядит лучше?

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

Или

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

Конечно, это дополнительный шаг, но что, если ваши условные проверки выполняют кучу других функциональных вещей, тогда цитаты и добавления начинают мешать кодированию функционально.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.