ブレードで変数の値を表示するのによく使う括弧。{{ }} と {!! !!}2種類あります。これらに関しての話です。
{{ }} と {!! !!}の違い
{{ }} と {!! !!}の違いは、いたって簡単です。前者はhtmlをエスケープして、後者はエスケープしません。と言っても??なので、具体的に以下のようなブレードを作成して、違いを見てみましょう。
{{ $x }}
{!! $x !!}
tinkerでこの$xに値を入れてブレードをビューすると、以下のようなHTML文が出力されます。
>>> view('test')->with(['x' => '<h1>hello</h1>'])->render();
=> """
<h1>hello</h1>\n
<h1>hello</h1>\n
"""
前者の表示は、HTMLのタグが見事にエスケープされていますが、後者はHTMLのタグがそのまま残っています。ブラウザでこれらを閲覧すると、
と表示の違いがはっきりします。
PHPにコンパイルされたブレード
先の例で使用したtest.blade.phpは、サーバーから表示される前にphpにコンパイルされてstorage/framework/viewsにキャッシュされます。コンパイルされたブレードの中身を見ると、
<?php echo e($x); ?> <?php echo $x; ?> <?php /**PATH /var/www/repos/l8x/resources/views/test.blade.php ENDPATH**/ ?>
お馴染みのphpファイルです(ブレードはphpファイル拡張子ですがphpファイルではありません)。なるほど単に標準のPHP関数のecho()を使用しています。しかし、前者において、e()という関数は標準のPHP関数ではありません。調べてみると、これはLaravelのヘルパーです。以下にその定義を掲載します。
...
/**
* Encode HTML special characters in a string.
*
* @param \Illuminate\Contracts\Support\DeferringDisplayableValue|\Illuminate\Contracts\Support\Htmlable|string|null $value
* @param bool $doubleEncode
* @return string
*/
function e($value, $doubleEncode = true)
{
if ($value instanceof DeferringDisplayableValue) {
$value = $value->resolveDisplayableValue();
}
if ($value instanceof Htmlable) {
return $value->toHtml();
}
return htmlspecialchars($value ?? '', ENT_QUOTES, 'UTF-8', $doubleEncode);
}
...
標準関数のhtmlspecialchars()が最終的にはHTMLタグをエスケープしていることわかります。
HtmlString
さて、ブレードで使用されている括弧の意味が解ったところで、先のtest.blade.phpを以下のように編集します。csrf_field()は、LaravelのCSRFトークンのためのヘルパー関数です。
{{ csrf_field() }}
これをtinkerで先と同様にレンダリングします。今回は変数の渡しなしです。
>>> view('test')->render()
=> "<input type="hidden" name="_token" value="">\n"
おかしいですね。二重波括弧なのに、HTMLタグがエスケープされていません。どうしてでしょう?
csrf_field()の定義を見てみましょう。
...
/**
* Generate a CSRF token form field.
*
* @return \Illuminate\Support\HtmlString
*/
function csrf_field()
{
return new HtmlString('<input type="hidden" name="_token" value="'.csrf_token().'">');
}
...
この関数が返しているのは、文字列ではなくHtmlStringのオブジェクトです。このオブジェクトがブレードでの括弧の変数の値とすると、エスケープ処理がされないのです。tinkerで試してみましょう。
>>> use Illuminate\Support\HtmlString;
>>> $x = new HtmlString('<h1>hello</h1>');
=> Illuminate\Support\HtmlString {#3517
html: "<h1>hello</h1>",
}
>>> e($x)
=> "<h1>hello</h1>"
HtmlStringを使う意味
表示される値にHTMLタグが含まれるかどうか前もってわかっていれば、{{ }} と {!! !!}の使いわけできますが、たいていはブレードを作成するのは開発者ではなくデザイナーさんです。HTML文を含むときに文字列ではなく、HtmlStringのオブジェクトとすれば、迷わずにいつも{{ }}の使用となります。
メルマガ購読の申し込みはこちらから。
