在php项目开发中,不同阶段的模板引擎选型可能不同,Smarty作为老牌模板引擎有大量存量模板,Blade凭借简洁的语法被新项目广泛使用,实现两者写法的兼容能大幅降低迁移成本。本文就讲解具体的实现方案。

核心差异分析
要实现兼容,首先要明确Smarty和Blade的语法差异,核心差异集中在变量输出、控制结构、注释三个部分:
- 变量输出:Smarty使用
{$var},Blade使用{{ $var }} - 控制结构:Smarty用
{if}{/if},Blade用@if@endif - 注释:Smarty是
{* 注释 *},Blade是{{-- 注释 --}}
基础兼容实现
我们可以通过自定义模板解析类,先统一转换两种语法的变量输出格式,再交给后续的模板引擎处理。首先实现变量输出的兼容解析:
<?php
class TemplateCompatibleParser {
/**
* 解析模板内容,兼容Smarty和Blade的变量输出语法
* @param string $templateContent 原始模板内容
* @return string 转换后的模板内容
*/
public function parseVariableOutput($templateContent) {
// 匹配Smarty变量语法 {$var} 或 {$arr.key}
$smartyPattern = '/{\$([a-zA-Z_][a-zA-Z0-9_.]*)}/';
// 替换为Blade变量语法 {{ $var }}
$templateContent = preg_replace($smartyPattern, '{{ $$1 }}', $templateContent);
// 匹配Blade变量语法 {{ $var }},这里不需要额外处理,后续交给Blade引擎即可
// 如果同时需要兼容Smarty引擎,可以反向替换为Smarty语法
return $templateContent;
}
}
// 使用示例
$parser = new TemplateCompatibleParser();
$oldSmartyTemplate = '欢迎用户:{$username},当前时间:{$time}';
$parsedContent = $parser->parseVariableOutput($oldSmartyTemplate);
echo $parsedContent;
// 输出:欢迎用户:{{ $username }},当前时间:{{ $time }}
?>
控制结构兼容
控制结构的兼容需要识别两种语法的控制标签,统一转换为目标引擎支持的格式,这里以统一转换为Blade语法为例:
<?php
class TemplateCompatibleParser {
// 之前的parseVariableOutput方法省略
/**
* 解析控制结构,兼容Smarty和Blade的if、foreach语法
* @param string $templateContent 原始模板内容
* @return string 转换后的模板内容
*/
public function parseControlStructure($templateContent) {
// 转换Smarty的if结构 {if $condition} -> @if($condition)
$templateContent = preg_replace('/{ifs+(.+?)}/', '@if($1)', $templateContent);
$templateContent = str_replace('{/if}', '@endif', $templateContent);
// 转换Smarty的foreach结构 {foreach $arr as $item} -> @foreach($arr as $item)
$templateContent = preg_replace('/{foreachs+(.+?)}/', '@foreach($1)', $templateContent);
$templateContent = str_replace('{/foreach}', '@endforeach', $templateContent);
// 转换Smarty的注释 {* 注释内容 *} -> {{-- 注释内容 --}}
$templateContent = preg_replace('/{*(.+?)*}/s', '{{-- $1 --}}', $templateContent);
return $templateContent;
}
}
// 使用示例
$parser = new TemplateCompatibleParser();
$smartyControlTemplate = '<div>
{* 用户列表循环 *}
{if $userList}
<ul>
{foreach $userList as $user}
<li>{$user.name}</li>
{/foreach}
</ul>
{/if}
</div>';
$parsedContent = $parser->parseControlStructure($smartyControlTemplate);
echo $parsedContent;
?>
完整适配流程
实际使用中,我们需要将解析逻辑整合,同时支持双向兼容,并且可以配置优先使用的引擎:
<?php
class TemplateEngineAdapter {
private $targetEngine; // 目标引擎,可选smarty或blade
public function __construct($targetEngine = 'blade') {
$this->targetEngine = $targetEngine;
}
/**
* 完整解析模板内容,兼容两种引擎写法
* @param string $content 原始模板内容
* @return string 适配目标引擎的模板内容
*/
public function adaptTemplate($content) {
if ($this->targetEngine === 'blade') {
// 转换为Blade语法
$content = $this->smartyToBlade($content);
} else {
// 转换为Smarty语法
$content = $this->bladeToSmarty($content);
}
return $content;
}
private function smartyToBlade($content) {
// 变量输出转换
$content = preg_replace('/{\$([a-zA-Z_][a-zA-Z0-9_.]*)}/', '{{ $$1 }}', $content);
// 控制结构转换
$content = preg_replace('/{ifs+(.+?)}/', '@if($1)', $content);
$content = str_replace('{/if}', '@endif', $content);
$content = preg_replace('/{foreachs+(.+?)}/', '@foreach($1)', $content);
$content = str_replace('{/foreach}', '@endforeach', $content);
// 注释转换
$content = preg_replace('/{*(.+?)*}/s', '{{-- $1 --}}', $content);
return $content;
}
private function bladeToSmarty($content) {
// 变量输出转换
$content = preg_replace('/{{s*\$([a-zA-Z_][a-zA-Z0-9_.]*)s*}}/', '{$$1}', $content);
// 控制结构转换
$content = preg_replace('/@ifs*((.+?))/', '{if $1}', $content);
$content = str_replace('@endif', '{/if}', $content);
$content = preg_replace('/@foreachs*((.+?))/', '{foreach $1}', $content);
$content = str_replace('@endforeach', '{/foreach}', $content);
// 注释转换
$content = preg_replace('/{{--(.+?)--}}/s', '{* $1 *}', $content);
return $content;
}
}
// 使用示例:老Smarty模板适配到Blade引擎
$adapter = new TemplateEngineAdapter('blade');
$oldTemplate = '{if $score > 60}及格{else}不及格{/if}';
$adapted = $adapter->adaptTemplate($oldTemplate);
echo $adapted; // 输出 @if($score > 60)及格@else不及格@endif
?>
注意事项
实际落地时需要注意几个问题:
- 正则匹配需要覆盖复杂的表达式,比如变量中包含函数调用、数组多维取值的场景,需要完善正则规则
- 如果模板中存在两种引擎的混合写法,需要定义优先级,避免解析冲突
- 转换后的模板建议做语法校验,避免转换过程中出现语法错误
这种兼容方案不需要修改原有模板引擎的核心代码,只需要在模板加载前做一层解析适配,对原有项目侵入性极低,适合渐进式项目升级场景。