Blade 是正则驱动的 PHP 代码生成器,将 .blade.php 编译为纯 PHP 脚本缓存执行;编译仅依赖文件修改时间,不解析语法树,原生 PHP 混写需注意作用域与转义风险。
Blade 不是解释执行的模板引擎,它本质是一套「正则驱动的 PHP 代码生成器」——所有 .blade.php 文件在首次访问时就被编译成纯 PHP 脚本,存入 storage/framework/views/,后续直接 include 执行,不经过任何解析。
BladeCompiler 类不构建 AST,也不做语法树分析,它靠一组预定义的正则表达式逐行扫描、匹配、替换。比如:
{{ $name }} → 匹配 /{{s*(.*?)s*}}/ → 替换为 <?php echo e($1); ?>
@if($user) → 匹配 /@ifs*((.*?))/ → 替换为 <?php if ($1): ?>
@endphp → 直接替换为 <?php endif; ?>(注意:不是 @endif 对应 @endphp,这是常见误解)这些规则全部定义在 IlluminateViewCompilersBladeCompiler::$compilers 数组里,顺序敏感——比如 @verbatim 必须最先处理,否则里面嵌套的 {{ }} 会被提前替换掉。
Blade 编译后的 PHP 文件名是源文件路径的 SHA256 哈希值,例如 resources/views/home.blade.php 可能对应 storage/framework/views/abc123...php。是否重编译只取决于两个条件:
filemtime() 大于缓存文件的 filemtime()
这意味着:修改了 .env 或配置不会触发重编译;清空 storage/framework/views/ 后首次访问必然编译;但如果你用 IDE 的「Safe Write」模式保存文件(先写临时文件再原子替换),可能因时间戳未更新导致缓存未刷新——这是本地开发时最常踩的坑。
Blade 允许混写原生 PHP,比如 <?php $x = 1; ?> 或 <script><?= $js ?></script>。这些代码块完全绕过正则替换,原样写入缓存 PHP 文件。问题在于:
include 时的局部作用域,$x 在 @if 块内声明,外面就不可见<?php echo $x; ?> 和 {{ $x }} 输出效果一样,但前者不经过 e() 转义,有 XSS 风险真正关键的不是“Blade 怎么工作”,而是理解它根本不运行时解析——所有逻辑都在缓存 PHP 文件里执行,所以性能瓶颈永远不在 Blade 本身,而在你写的 PHP 代码或数据库查询上。