PHPでsprintf関数を使用する理由


188

私はPHP関数sprintf()についてもっと学びたいと思っていますが、まだ混乱しているのでphp.netはあまり役に立ちませんでした。なぜそれを使いたいのですか?

以下の私の例を見てください。

なぜこれを使うのか:

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

これが同じことを行い、IMOを記述しやすい場合:

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

ここで何か不足していますか?


40
+1、いい質問です。自分ではめったに使用しないので、答えを見たいです。
zombat 2009

6
2つの例は同等ではないことに注意してください。最初の例は単に結果を$outputに代入し、2番目の例はそれを代入してechoいます。
ダニエルプライデン2009

たくさんのものをつなげるときに個人的に使っています。主に読みやすさのために、それが私がそれを役に立つと思うのは本当にそれからです。
AlexMorley-Finch 2014

回答:


130

sprintf は、元のprintfのすべてのフォーマット機能を備えています。つまり、単に文字列に変数値を挿入するだけではありません。

たとえば、数値形式(16進数、10進数、8進数)、小数点以下の桁数、パディングなどを指定します。Googleのprintfを使用すると、多くの例を見つけることができます。printfの上のWikipediaの記事は、あなたが始める必要があります。


46
数年前、私はゼロ詰めの数値のための素晴らしい関数を書きました。私が簡単にできることにsprintf('%03d', $num)
気づく

5
PHP sprintfにはすべてのフォーマット機能があります...実際に重要な機能が欠け%,8dています。たとえば、8桁を正しく揃えてカンマで区切った整数を取得する場合などです。使い方はnumber_formatではあまり便利であるprintfスタイル。
e2-e4 2010年

3
@DisgruntledGoatそのフォーマット文字列( '%03d')を分解できますか?本当に助かると思います。ありがとう。
Smee氏、2014年

3
表示する引数を繰り返して並べ替えることもできます。例えばsprintf('%2$s %1$s, my name is also %1$s.', 'World', 'Hello');その結果Hello World, my name is also World.
fyrye

77

sprintfには多くの使用例がありますが、私がそれらを使用する1つの方法は、次のような文字列を格納することです: 'Hello、My Name is%s'データベースに、またはPHPクラスの定数として。そうすれば、その文字列を使用したいときに、これを簡単に実行できます。

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

本質的には、コードをある程度分離することができます。コードの多くの場所で 'Hello、My Name is%s'を使用すると、1つの場所で '%s is my name'に変更でき、各インスタンスに移動して移動する必要なく、他のすべての場所で自動的に更新されます。連結。


8
この。次に、番号付きの引数と翻訳を追加します:]
Konerak 2012

46

のもう1つの用途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 '06 / 11/12

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
たとえそれらが元の文字列に存在しない場合でも、それらを翻訳に入れれば機能します。
16年

17

私が見つけた最大の理由は、人々が必要に応じて翻訳および順序付けできる言語ファイルにすべての言語文字列を配置できることです-それでも、文字列の形式に関係なく、表示したいユーザー名。

たとえば、サイトの上部に「おかえり[[ユーザー]]」と表示されます。あなたが知らないか気にしていないプログラマーとして、UIの連中がどのように書くかをユーザー名がメッセージのどこかに表示されることを知っているだけです。

そのため、メッセージが実際に何であるかについて心配することなく、メッセージをコードに埋め込むことができます。

Langファイル(EN_US):

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

次に、これを実際のphpコードで使用することにより、任意のタイプのメッセージを任意の言語でサポートできます。

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

言語ファイルを作成することについて心配する必要はありませんでしたが、これは私にとって最も便利な使用法の1つであるように思われます
JasonDavis

この例は、私が多言語アプリケーションをあまり実行していないので、私にとっても完全に理にかなっています。
MKN Webソリューション2014

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

前述のように、入力データをフォーマットできます。たとえば、2 dp、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 -inactive-

@duskwuff-そのまま使用すると、そのとおりです。申し訳ありませんが、回答を修正しました。
Samuel Jaeschke

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年前にこれを尋ねて、思い出せないということも言及する価値があります。私はいつかそのための場所を見つけたいと思っていますし、そこに場所があると信じていますが、何年も前にこの質問をして以来、私がそれを使用しなかったと思うのはおかしいです!
JasonDavis 2015

これは、PHPでPDOの変数を設定するのと似ています。また、可読性の引数を指定する場合sprintf()は、プレースホルダー付きの文字列が1行にあり、値が1行または複数の行の下にある複数行に分割して使用することをお勧めします。コース。説明した方法でデモを使用する... i.imgur.com/DFi3ur8.png
JasonDavis

ストアドプロシージャと組み合わせて準備されたステートメントは、sprintfではなく、SQLインジェクションを防ぐための最良の方法です。文字列に単一引用符が含まれている場合でも、sprintfを使用して簡単にsql injectを実行できます
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.";

WHichは次のように簡単に書くことができます

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の脆弱性まで開きます。
サードパーティ、2015

HEREDOC構文を使用することもできます。私の意見では、どちらもsprintf構文より読みやすいです。
サードパーティ、2015

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を使用するもう1つの理由は、ユーザーが特定の値の出力形式を定義できるようにすることです。ユーザーがsprintf互換の出力形式を安全に定義できるようにすることができます。

ああ、あなたの例は実際にはある部分で間違っています。sprintf文字列を返しますが返しechoません- echoすぐに出力して何も返しませんが、sprintfただ返します。


3
  1. C / C ++を使用している場合は、sprintf関数に慣れているはずです。

  2. 2行目は効率が悪い可能性があります。Echoは出力コマンドとして設計されていますが、sprintfは文字列トークンの置換を行うように設計されています。私はPHPの人間ではありませんが、エコーに関連するオブジェクトが他にもあると思います。Javaのように動作する場合、リストに何かが追加されるたびに新しい文字列が作成されるため、最終的に4つの文字列が作成されます。


Javaの最近のエディションでは、ストリングの連結を舞台裏でStringBuilderに変換します。
ロデオクラウン2009

1
PHPの文字列はオブジェクトではありません。2番目の例では、関数呼び出しの代わりに言語構成を使用しているため、気付かれないほど高速になります。
タムリン2013

3

時々私はこのようなものを手に入れました、それをもう少し読みやすくすると思います:

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

3

私は通常、sprintfを使用して、ユーザー入力からのIDが整数であることを確認します。次に例を示します。

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

数値をさまざまな表現でフォーマットすることも非常に便利です(8進数、小数点以下の桁数の制御など)。


intval($ _ GET ["article_id"])を使用する方が簡単ではないですか?まあ、実際にはより多くのタイピングをした...★注意事項ご使用方法」ダグnabbitダウン。
user97410

このタイプのコードでは、組み込みのmysql_real_escape_string()を使用することをお勧めします。
bruno.braga 2012年

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の最も重要なポイントですが、複雑な例では「欠落」から果物を作成しています。果物:)、それぞれが繰り返しのみを示す%d(およびabs()トピックに対しては無関係である、)、代わりに(数書式設定オプションの茄多の一部を示すのでしょう関連があるが)、私は私の心を変えました。しかし、回答を更新しても、冷蔵庫には賛成票が残っています。:) Thx、乾杯!
Sz。

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()本当に理解することは難しいことではありません。

異なるものの1つ 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。$ b。$ c。$ d。$ e。$ 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);

確かに追加の手順ですが、条件付きチェックで他の機能的なことを実行すると、引用と追加が機能的なコーディングの邪魔になり始めます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.