ブレードで変数の値を表示するのによく使う括弧。{{ }} と {!! !!}2種類あります。これらに関しての話です。

{{ }} と {!! !!}の違い

{{ }} と {!! !!}の違いは、いたって簡単です。前者はhtmlをエスケープして、後者はエスケープしません。と言っても??なので、具体的に以下のようなブレードを作成して、違いを見てみましょう。

resources/views/test.blade.php
{{ $x }}
{!! $x !!}

tinkerでこの$xに値を入れてブレードをビューすると、以下のようなHTML文が出力されます。

>>> view('test')->with(['x' => '<h1>hello</h1>'])->render();
=> """
   &lt;h1&gt;hello&lt;/h1&gt;\n
   <h1>hello</h1>\n
   """

前者の表示は、HTMLのタグが見事にエスケープされていますが、後者はHTMLのタグがそのまま残っています。ブラウザでこれらを閲覧すると、

と表示の違いがはっきりします。

PHPにコンパイルされたブレード

先の例で使用したtest.blade.phpは、サーバーから表示される前にphpにコンパイルされてstorage/framework/viewsにキャッシュされます。コンパイルされたブレードの中身を見ると、

storage/framework/views/4ad4f1be91eef212ba8e4b67c67ee18a0f640a9a.php
<?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のヘルパーです。以下にその定義を掲載します。

vendor/laravel/framework/src/Illuminate/Support/helpers.php
...
   /**
     * 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トークンのためのヘルパー関数です。

resources/views/test.blade.php
{{ csrf_field() }}

これをtinkerで先と同様にレンダリングします。今回は変数の渡しなしです。

>>> view('test')->render()
=> "<input type="hidden" name="_token" value="">\n"

おかしいですね。二重波括弧なのに、HTMLタグがエスケープされていません。どうしてでしょう?

csrf_field()の定義を見てみましょう。

vendor/laravel/framework/src/Illuminate/Support/helpers.php
...
    /**
     * 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のオブジェクトとすれば、迷わずにいつも{{ }}の使用となります。

メルマガ購読の申し込みはこちらから。

By khino