Skip to main content
要从包中提供 Blade 语法,需要把将模板转换为 PHP 的处理与执行生成的 PHP 的处理区分开来。如果在编译时嵌入当前的配置值,缓存的视图可能会一直显示旧值。 本页参考 Laravel 官方文档 13.x 以及 Framework v13.37.0 的实现,对包开发基础进行深入讲解。常规模板语法请参阅 Blade,视图的命名空间与发布请参阅包视图的覆盖与更新。

区分注册、编译与执行

传给 Blade::directive() 的回调返回的不是要显示的值,而是要生成的 PHP 代码字符串。参数 $expression 也不是已求值的值,而是写在模板中的 PHP 表达式。 view:cache 也会执行编译。在指令的生成回调中,不要获取当前用户、写入数据库或调用外部 API。

使用包专属的名称注册

作为示例,我们提供一个在配送编号前显示所配置标签的 @acmeCourierLabel($code)。前提是通过 Composer 的 PSR-4 将 Acme\Courier\ 映射到 src/,并通过自动发现或手动方式注册服务提供者。
src/CourierServiceProvider.php
本示例约定 courier.label 为字符串、courier.enabled 为布尔值。配置文件的分发与合并请参阅包配置的合并与缓存。 注册在常规服务提供者的 boot() 中进行,不要用 runningInConsole() 条件包裹。HTTP 渲染和 Artisan 的 view:cache 都需要相同的扩展。也要避免把只注册 Blade 扩展的服务提供者设为延迟提供者,因为它在其他服务被解析之前不会启动。

参数以表达式而非值的形式接收

在这个模板中,回调接收到的是字符串 $code。生成的 PHP 如下所示。
config() 与 $code 的求值发生在执行这段 PHP 的时刻。这与回调自身读取 config() 并返回固定字符串的实现不同。 经确认,callCustomDirective() 会去掉外层圆括号并 trim 表达式,然后传给回调。它不会把参数转换为 PHP 值,也不会拆分为单独的参数。本示例将其作为传入一个必需表达式的语法公开。 处理多个参数时,不要简单地用逗号 explode()。数组、方法调用和字符串字面量中也可能包含逗号。如果要处理属性或复杂的 HTML,作为 Blade 组件提供更容易划分职责。
模板中的表达式是由可信开发者编写的 PHP。不要用用户输入拼接模板源码。另外,自定义指令中的 echo 不会自动获得常规 {{ }} 的转义。本示例中,生成的 PHP 显式调用了 e()。

名称冲突也是兼容性问题

directive() 以名称为键将处理器保存到数组中。同名注册会覆盖之前的注册,并且 compileStatement() 会优先选择自定义指令,而不是内置的转换方法。官方测试中也有通过自定义注册覆盖 foreach 的用例。 请避免使用 label、enabled 等通用名称以及内置名称,并加上包专属的前缀。将使用者在模板中使用的名称和参数视为公开 API,变更时提供迁移步骤。

条件分支使用 Blade::if 在运行时判断

上面服务提供者中注册的条件可以这样使用。
Blade::if() 在保存条件回调之后,会注册用于开始、unless、else 和结束的指令。本示例的开始部分会被转换为以下 PHP。
检查配置的条件回调由 check() 在运行时调用。这并不是在编译时固定 true 或 false 结果的处理。即使是使用已编译视图的 HTTP 进程,也需要注册条件回调。 这种语法只用于切换显示内容,并不是对配送操作的授权。访问控制也要在路由或操作一侧实施。

包更新后视图未必会自动重新生成

经确认,Compiler::isExpired() 会检查缓存是否存在,并根据配置检查原始视图与已编译文件的更新时间。它不会把服务提供者中编写的指令变更作为依赖文件进行追踪。 官方文档也建议在修改指令逻辑后,使用 view:clear 删除缓存。请在使用方应用的部署流程中,在更新的包与使用者的视图保持一致之后执行。
view:cache 在生产环境中进行预编译时执行。不要在包的 boot() 中每次都清除缓存,也不要在安装时擅自改写使用方应用的部署流程。配置缓存的更新和长驻进程的重新加载,也请遵循使用环境的常规部署步骤。

分别验证编译结果与渲染结果

首先,在注册了上述服务提供者的测试用 Laravel 应用中,验证生成的 PHP。以下是添加到继承 Tests\TestCase 的 Feature 测试中的方法。
这个测试可以确认生成 PHP 的约定,但无法验证运行时的转义和条件分支。在实际的包中,还要添加视图渲染和更新时的验证。

相关页面

包视图的覆盖与更新

了解命名空间的查找顺序以及维护已发布模板的方法。

包的缓存与 optimize 集成

了解将自有缓存的构建与删除集成到部署流程中的方法。

参考的一手资料

最后修改于 2026年10月17日