LaravelのBladeドキュメントは丁寧でわかりやすいですが、わかりやすさのために切り捨てられている部分もあります。例えばBladeの制御構文がいくつか抜け落ちています。この記事では探し方を紹介します。探し方が分かればバージョンが変わっても平気です。
Bladeテンプレート 5.7 Laravel
探すことをプログラムに任せる直接的な解決策があります。そういうプラグインのあるエディタを使用してそのプラグインを入れましょう。PhpStormならばBlade Supportがあり次の画像の様に、色付けと予測を行ってくれます。
Blade Support – Plugins | JetBrains
Bladeの元を探そうとしてもクラスやメソッドの呼び出しを辿って見つけることは難しいです。というのもLaravelはそのソースコード内で特定の名前のクラス、メソッドをまとめて呼び出したり、その場でPHPの構文を作ったりすることで根本のコードを小さく保っているためです。例えば次の様なコードが現れます。
/** * Register the engine resolver instance. * * @return void */ public function registerEngineResolver() { $this->app->singleton('view.engine.resolver', function () { $resolver = new EngineResolver; // Next, we will register the various view engines with the resolver so that the // environment will resolve the engines needed for various views based on the // extension of view file. We call a method for each of the view's engines. foreach (['file', 'php', 'blade'] as $engine) { $this->{'register'.ucfirst($engine).'Engine'}($resolver); } return $resolver; }); }
このためLaravelの中を探す時はそれっぽいクラス名、メソッド名を用いた正規表現によって隠された呼び出し元を探す方法が有効です。肝心のBlade構文を字句解析(大雑把いえば文字列を意味のある字句に区切る処理)している部分は次です。この部分はViewのProvider周りから呼び出されています。
// vendor/laravel/framework/src/Illuminate/View/Compilers/BladeCompiler.phpの内部 /** * All of the available compiler functions. * * @var array */ protected $compilers = [ 'Comments', 'Extensions', 'Statements', 'Echos', ]; /** 省略 **/ /** * Parse the tokens from the template. * * @param array $token * @return string */ protected function parseToken($token) { [$id, $content] = $token; if ($id == T_INLINE_HTML) { /** ここから */ foreach ($this->compilers as $type) { $content = $this->{"compile{$type}"}($content); } /** ここまでが重要 */ } return $content; }
$this->{“compile{$type}”}($content);を満たすメソッドで字句解析をしています。これを満たすメソッドで@以下を解析しているのが次のcompileStatementsです。
/** * Compile Blade statements that start with "@". * * @param string $value * @return string */ protected function compileStatements($value) { return preg_replace_callback( '/\B@(@?\w+(?:::\w+)?)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', function ($match) { return $this->compileStatement($match); }, $value ); } /** * Compile a single Blade @ statement. * * @param array $match * @return string */ protected function compileStatement($match) { if (Str::contains($match[1], '@')) { $match[0] = isset($match[3]) ? $match[1].$match[3] : $match[1]; } elseif (isset($this->customDirectives[$match[1]])) { $match[0] = $this->callCustomDirective($match[1], Arr::get($match, 3)); /** ここから*/ } elseif (method_exists($this, $method = 'compile'.ucfirst($match[1]))) { $match[0] = $this->$method(Arr::get($match, 3)); } /** ここまで重要 ucfirstは最初の一文字が大文字なら小文字にする関数*/ return isset($match[3]) ? $match[0] : $match[0].$match[2]; }
到達しました。BladeCompilerのインスタンスに引っ付いているcompileHogeなメソッドがあれば@hogeが動作するということです。後はBladeCompilerに生えているメソッド一覧を見て終わりです。
多いです。使いこなせている人はいるのでしょうか。