この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:atom
更新日時:2026-06-11 07:12:00

タイトル: テンプレートエンジン
SEOタイトル: PHP のテンプレートエンジン比較(Twig / Blade / Smarty / Plates / Mustache)

この記事の要点
  • テンプレートエンジン = HTML の中に変数や制御構文を埋め込み、HTML エスケープを自動化するライブラリ
  • 主要 5 つ: Twig (Symfony 標準・モダン) / Blade (Laravel 専用) / Smarty (老舗) / Plates (素の PHP に近い) / Mustache (ロジックレス・多言語)
  • 共通機能: 変数展開・制御構文・テンプレート継承 (extends)・include / partial・フィルタ・自動エスケープ
  • パフォーマンス: 初回コンパイルして PHP に変換 → 以降は コンパイル済キャッシュ使用
  • 素の PHP を使う場合は <?= htmlspecialchars($x, ENT_QUOTES, "UTF-8") ?> を毎回書く必要 → 漏れると XSS の温床

なぜテンプレートエンジンを使うのか

素の PHP でも HTML を出力できますが、以下の問題があります:

  • HTML エスケープが手動 → 漏れると XSS
  • ロジックと表示が混在しやすく可読性が悪い
  • 共通レイアウトの継承が冗長(毎ファイルにヘッダー・フッターの include)
  • 非エンジニア(デザイナー)に PHP を触らせたくない

テンプレートエンジンはこれらを制約付き構文 + 自動エスケープで解決します。

5 大テンプレートエンジンの比較

エンジン用途特徴
TwigSymfony / フレームワーク非依存モダン・高速・継承・サンドボックス。Drupal でも採用
BladeLaravel 専用@directive 構文・コンポーネント・スロット
Smarty老舗 (2001-)歴史長くドキュメント豊富。記法はやや古い
Plates素の PHP に近い独自構文学習不要・軽量・継承サポート
Mustacheロジックレス・多言語JS/Ruby/Go 等にも実装あり。{{var}} のみ

Twig の基本

{# layout.twig - 共通レイアウト #}
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}デフォルト{% endblock %}</title>
</head>
<body>
  <header>共通ヘッダー</header>
  {% block content %}{% endblock %}
  <footer>&copy; {{ "now"|date("Y") }}</footer>
</body>
</html>

{# page.twig - 継承 #}
{% extends "layout.twig" %}

{% block title %}記事一覧{% endblock %}

{% block content %}
  <h1>{{ pageTitle }}</h1>

  {% if articles is not empty %}
    <ul>
    {% for a in articles %}
      <li><a href="/article/{{ a.id }}">{{ a.title }}</a> ({{ a.views|number_format }} views)</li>
    {% else %}
      <li>記事がありません</li>
    {% endfor %}
    </ul>
  {% endif %}

  {# 自動エスケープ #}
  {{ user.name }}            {# <script> はエスケープされる #}
  {{ user.bio|raw }}         {# raw = エスケープしない(信頼できる時のみ) #}
  {{ price|number_format(0, ',', '.') }}
{% endblock %}

PHP からの呼び出し:

<?php
require __DIR__ . '/vendor/autoload.php';

$loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/templates');
$twig = new \Twig\Environment($loader, [
    'cache' => __DIR__ . '/cache',
    'auto_reload' => true,   // 開発時は変更検知
    'autoescape' => 'html',
]);

echo $twig->render('page.twig', [
    'pageTitle' => '記事一覧',
    'articles' => [
        ['id' => 1, 'title' => 'PHP 入門', 'views' => 12345],
        ['id' => 2, 'title' => 'Laravel', 'views' => 9876],
    ],
    'user' => ['name' => 'taro', 'bio' => '<b>Hello</b>'],
]);

Blade の基本(Laravel)

{{-- layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head>
  <title>@yield('title', 'デフォルト')</title>
</head>
<body>
  @include('partials.header')
  @yield('content')
  @stack('scripts')
</body>
</html>

{{-- pages/articles.blade.php --}}
@extends('layouts.app')

@section('title', '記事一覧')

@section('content')
  <h1>{{ $pageTitle }}</h1>

  @forelse ($articles as $a)
    <div>
      <a href="/article/{{ $a->id }}">{{ $a->title }}</a>
      ({{ number_format($a->views) }} views)
    </div>
  @empty
    <p>記事がありません</p>
  @endforelse

  {{ $user->name }}        {{-- 自動エスケープ --}}
  {!! $user->bio !!}        {{-- エスケープ無効(信頼できる時のみ) --}}
@endsection

@push('scripts')
  <script src="/js/articles.js"></script>
@endpush

コンポーネント(Blade の現代的な機能):

{{-- resources/views/components/alert.blade.php --}}
@props(['type' => 'info'])

<div class="alert alert-{{ $type }}">
  {{ $slot }}
</div>

{{-- 使用 --}}
<x-alert type="success">
  保存しました!
</x-alert>

Smarty / Plates / Mustache の例

{* Smarty 4 *}
{extends file="layout.tpl"}
{block name="content"}
  <h1>{$pageTitle|escape}</h1>
  {foreach $articles as $a}
    <li>{$a.title|escape}</li>
  {/foreach}
{/block}
<?php
// Plates — 素の PHP に近い
// templates/page.php
$this->layout('layout', ['title' => $pageTitle]);
?>
<h1><?= $this->e($pageTitle) ?></h1>
<?php foreach ($articles as $a): ?>
  <li><?= $this->e($a['title']) ?></li>
<?php endforeach; ?>
{{! Mustache - ロジックレス }}
<h1>{{pageTitle}}</h1>
<ul>
  {{#articles}}
    <li>{{title}} ({{views}} views)</li>
  {{/articles}}
  {{^articles}}
    <li>記事がありません</li>
  {{/articles}}
</ul>

選び方の指針

状況推奨
Laravel を使うBlade(標準・統合済)
Symfony を使うTwig(標準・統合済)
フレームワーク非依存・新規Twig(最も成熟)
軽量・素の PHP に近い構文がいいPlates
JS / Ruby と同じテンプレートを共有Mustache
既存資産が大量にあるそのまま継続(Smarty 等)

パフォーマンス: コンパイルキャッシュ

主要エンジンは初回ロード時にテンプレートを純粋な PHP コードへコンパイルし、cache/ ディレクトリに保存します。2 回目以降はキャッシュされた PHP を require するだけなので、素の PHP と遜色ない速度になります。

デプロイ時のキャッシュ操作:

# Laravel Blade
php artisan view:clear
php artisan view:cache

# Twig はコンパイル済キャッシュをクリア(手動)
rm -rf var/cache/prod/twig

# Smarty
$smarty->clearCompiledTemplate();

FAQ

Q: 素の PHP では駄目?
A: 小さなページなら可。ただし htmlspecialchars() を毎回書くのは現実的に漏れる → XSS の温床。テンプレートエンジンは自動エスケープが最大の利点。

Q: Twig と Blade はどちらが速い?
A: 大きな差はなし。両方とも初回コンパイル後はキャッシュされた PHP として動く。OPcache 有効化のほうが影響大。

Q: テンプレートに DB クエリを書いていい?
A: 非推奨。表示ロジックとデータ取得は分離(MVC)。テンプレート内では 渡された変数を表示するだけに留めるとメンテしやすい。