web-dev-qa-db-ja.com

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

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;

ここに何かが足りませんか?

183
JasonDavis

sprintfには、元のprintfのすべての書式設定機能があります。つまり、文字列に変数値を挿入するだけでなく、それ以上のことができます。

たとえば、数値形式(16進数、10進数、8進数)、10進数の数、パディングなどを指定します。 Google for printfを使用すると、多くの例が見つかります。 printfに関するwikipediaの記事 から始めることができます。

125
Isak Savo

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」に変更でき、各インスタンスに移動して移動することなく、他のすべての場所で自動的に更新されます連結。

76
macinjosh

sprintfのもう1つの用途は、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 を使用しますが、アイデアは得られます。


46
Ken Keenan

翻訳が簡単です。

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

これははるかに理にかなっており、他の言語に翻訳するのがはるかに柔軟です

36
raspi

私が見つけた最大の理由は、必要に応じて人々が翻訳して注文できる言語ファイルにすべての言語文字列を配置できることです-しかし、文字列の形式に関係なく、あなたはまだ表示したいことを知っていますユーザー名。

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

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

言語ファイル(EN_US):

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

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

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

なぜあなたはそれを使いたいですか?

言語文字列に(外部)ソースを使用する場合、非常に便利です。特定の多言語文字列に一定数の変数が必要な場合は、正しい順序を知るだけで済みます。

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のすべての機能が付属しているため、次のように、さまざまなタイプの変数をフォーマットするためのワンライナーです。

9
John Weisz

前述のように、入力データのフォーマットが可能です。たとえば、2dp、4桁の数字などを強制します。MySQLクエリ文字列を構築するのに非常に便利です。

もう1つの利点は、パラメーターを入力するのと同じように、文字列のレイアウトを、そこに入力されるデータから分離できることです。たとえば、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挿入攻撃を防止します。 サニタイズされていない入力を解析すると、サイトとサーバーがハッキングされます。 (もちろん、コードによって完全に構築され、安全であることが保証されている変数は例外です。)

8
Samuel Jaeschke

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()と同等ですが、(変数に)返す代わりに、フォーマットされた文字列を出力します。

どちらが読みやすいですか?

6
kenorb

私も最近使っていない限り同じことをしています。ユーザー入力に基づいてドキュメントを生成する場合、これは便利です。

"<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);
4
swordfish

この:

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

私の意見では、これは読みやすくなっていますが、ローカライズまたはフォーマットの用途を見ることができます。

4
Thomas Tremain

典型的なケースのいくつかは、出力形式をより正確に制御する必要がある場合です。たとえば、特定の値の長さに応じて、特定の値の前に特定のスペースが埋め込まれていることを確認したり、特定の正確な形式で数値を出力したりするのは難しい場合があります。

たくさんの例があります PHPマニュアル

また、「書きやすい」という例に出てくるもの。エコーは書きやすいかもしれませんが、特に多くの変数がある場合、sprintfは読みやすいです。

Sprintfまたはprintfを使用するもう1つの理由は、ある値の出力形式をユーザーに定義させたいということかもしれません-sprintf互換の出力形式を安全に定義できるようにすることができます。

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

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進数、小数点以下の桁数の制御など)で数値をフォーマットすることも非常に便利です。

3
Castro
  1. C/C++を使用したことがある場合は、sprintf関数に慣れています。

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

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

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

時々私はこのようなものを手に入れました。

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

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ステートメントの左側は、文字列と期待値のタイプを明確に表し、右側は使用される変数とそれらの操作方法を明確に表します。

3
Ro Mc

Sprintfを使用するための本当に良いユースケースは、数字のパディング形式を出力することです。また、文字列に異なる型を混在させる場合もあります。多くの場合読みやすく、同じ変数の異なる表現、特に数値表現を簡単に印刷できます。

2
Lloyd Moore

引数はテンプレートを使用する場合と同じです。 Textsleevを実際の変数値から分離する必要があります。言及されているsprintfの追加の機能に加えて、それは単なるスタイルのことです。

2
worenga

通常の連結よりも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
user8241064

sprintf()printf()と非常によく似ています。 printf()を詳細に知っている場合、sprintf()およびvsprintf()を理解することは本当に難しくありません。

sprintf()printf()と異なる点の1つは、関数からの出力を直接取得/エコーしないため、関数からの出力をキャッチする変数を宣言する必要があることです。次のコードスニペットを見てみましょう。

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"

お役に立てば幸いです。

1
Vuong

ユーザーへのメッセージやその他の「きれいな」タイプの機能に使用します。たとえば、ユーザー名を使用することがわかっている場合。

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

確かに追加のステップですが、条件付きチェックが他の機能的なものを大量に行うと、引用と追加が機能的なコーディングの邪魔になります。

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.4507689476013が必要です

「$ a $ b $ c $ d $ e $ f」には1.9958319664001sが必要です

sprintf( '%s%s%s%s%s%s'、$ a、$ b、$ c、$ d、$ e、$ f)には9.1771278381348sが必要です

0
g3rdn

1つの「出力」、もう1つの「戻り値」は、主な違いの1つです。

printf() 出力

sprintf() 戻り値

0