概要
PHPファイル自身をsmartyやmustache等のテンプレートエンジンのテンプレートとして適用できるのかという思考実験をしてみたら簡単にできたので公開してみる。
何がうれしいの?
テンプレートエンジンを実行してテンプレートを展開するコードをテンプレートに埋め込めれば、
PHPファイル1つ(テンプレートエンジン本体のソースコードを除く)でテンプレートの実行結果が確認できてテンプレートの製作がはかどりそうと思った。
やり方
PHPファイル本体はfile_get_contents(__FILE__)
で取得できるので、PHP部分<? ~ ?>
を正規表現で取り除いてからテンプレートエンジンに渡すだけ。
なぜsmartyとmustache?
どちらも最悪ZIP解凍したファイル群をフォルダごとアップロードするだけでテンプレートエンジンの実行ができるから。
だいたいのテンプレートエンジンはそうなのかもしれないけど。要はたまたま目についただけ。
一応mustacheは他の言語というかJavaScriptにも公式対応しているので夢が広がりそうと思った部分もある。
コード
smartyの場合
<?php
$result = ['test' => 'テスト'];
if ($_SERVER['REQUEST_METHOD'] == "GET") {
//PHP部分を取り除くプリフィルタ
function phpfilter($source)
{
return preg_replace('/\<\?(.*?)[?]>/s', '', $source);
}
define('SMARTY_DIR', '/var/www/html/php/Smarty/libs/');
require_once(SMARTY_DIR . 'Smarty.class.php');
$smarty = new Smarty();
$smarty->template_dir = './';
$smarty->compile_dir = './output';
$smarty->registerFilter('pre', 'phpfilter'); //プリフィルタの設定
$smarty->assign('result', $result);
$smarty->display(__FILE__); //このファイル自身をテンプレートにしてレンダリング。
} else {
echo json_encode($result);
}
exit;
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>{$result.test}</title>
</head>
<body>
{$result.test}
</body>
</html>
Mustacheの場合
<?php
$data = ['test' => 'テスト'];
//Mustacheエンジンのロード
require_once('/var/www/html/php/Mustache/Autoloader.php');
Mustache_Autoloader::register();
$engine = new Mustache_Engine(array(
'loader' => new Mustache_Loader_StringLoader(),
'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__)),
), array('entity_flags' => ENT_QUOTES));
$source = file_get_contents(__FILE__); //自分自身のファイルを取得
$source = preg_replace('/\<\?(.*?)[?]>/s', '', $source); //PHPコード部分を削除
$contents = $engine->render($source, $data); //PHPコードを削除した文字列をテンプレートにレンダリング
echo $contents;
exit();
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>{{test}}</title>
</head>
<body>
{{test}}
</body>
</html>
BladeOneの場合
laravelから切り離したBladeテンプレート独立版なんてのがあったんですね
<?php
$data = ['name' => 'World'];
include __DIR__.'/lib/BladeOne.php';
use eftec\bladeone\BladeOne;
class CustomBladeOne extends BladeOne
{
//getFileを継承してテンプレートファイルを加工する
public function getFile($fullFileName): string
{
$source = parent::getFile($fullFileName);
$source = preg_replace('/\<\?(.*?)[?]>/s', '', $source); //PHPコード部分を削除
return $source;
}
}
$blade = new CustomBladeOne(__DIR__, __DIR__.'/compiles');
$blade->setFileExtension('.php');
$contents = $blade->run(basename(__FILE__, '.php'), $data);
echo $contents;
exit;
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bladeテンプレートのテスト。</title>
</head>
<body>
<h1>Bladeテンプレートのテスト。</h1>
<p>Hello, {{$name}}.</p>
</body>
</html>
実装した感想
mustache版を実装して思ったことは、これリクエストに応じて適用済みのテンプレートを返したりテンプレートだけを返してJavascript側でテンプレート適用させたりすればSSR付きのSPAっぽいことできるんじゃね?って思いました。