news 2026/8/24 10:45:53

揭秘laravel-blade-javascript责任链模式:6个Transformer协作转换任意值到JavaScript

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
揭秘laravel-blade-javascript责任链模式:6个Transformer协作转换任意值到JavaScript

揭秘laravel-blade-javascript责任链模式:6个Transformer协作转换任意值到JavaScript

【免费下载链接】laravel-blade-javascriptA Blade directive to export variables to JavaScript项目地址: https://gitcode.com/gh_mirrors/la/laravel-blade-javascript

laravel-blade-javascript是一个 Laravel 扩展包,它提供了一个@javascriptBlade 指令,让你可以把 PHP 变量一键导出到 JavaScript中:在模板里写一行@javascript('key', 'value'),页面渲染后浏览器里就能直接用key这个变量。

那么问题来了:PHP 里什么都有——字符串、布尔、数组、对象、null……它是怎么把"任意值"安全地变成合法的 JavaScript 的?答案就是本项目源码中隐藏的责任链模式(Chain of Responsibility)🎯

先看效果:一个指令打通 PHP 与 JavaScript

安装只需一条命令:

composer require spatie/laravel-blade-javascript

在 Blade 模板中使用:

@javascript('key', 'value')

页面最终输出:

<script>window['key'] = 'value';</script>

如果不想污染全局,还可以在配置文件 config/blade-javascript.php 里设置namespace,把变量收进独立命名空间,避免命名冲突。

责任链模式是什么?为什么这里需要它

想象一支流水线:一个值进入后,依次询问每个转换器——"你能处理它吗?"谁能处理,谁来接手,其他人继续待命。这就是责任链模式:

  • 每个节点只负责一种职责(单一职责,代码短小好测试)
  • 新增类型只需加一个节点,不用改老代码(开闭原则)
  • 拒绝处理时自动"传递"给下一个,链路末段统一兜底报错

laravel-blade-javascript 正是这样实现的。所有转换器都实现同一个接口,定义在 src/Transformers/Transformer.php:

interface Transformer { public function canTransform($value): bool; // 我能处理吗? public function transform($value); // 那就交给我 }

两个方法、一种契约,六个实现。

Renderer:责任链的"总调度"

整条链的发起者是 src/Renderer.php。它在构造函数里注册了 6 个转换器,按固定顺序组成链条:

protected $transformers = [ ArrayTransformer::class, BooleanTransformer::class, NullTransformer::class, NumericTransformer::class, ObjectTransformer::class, StringTransformer::class, ];

真正的"传递"发生在getTransformer()方法中——逐个询问,命中即返回:

public function getTransformer($value): Transformer { foreach ($this->getAllTransformers() as $transformer) { if ($transformer->canTransform($value)) { return $transformer; } } throw Untransformable::noTransformerFound($value); }

一句话概括:先问遍所有人,没人能处理就抛Untransformable异常,错误信息直接告诉你是哪个值没被转换,排查体验极佳。

6个Transformer逐一揭秘:各自认领什么任务?

1️⃣ ArrayTransformer —— 数组与集合的"翻译官"

位于 src/Transformers/ArrayTransformer.php,用is_array()认领所有数组,直接json_encode()变成 JSON 对象。这是 PHP 数组与 JS 对象之间最自然的桥梁。

2️⃣ BooleanTransformer —— 布尔值的类型对齐器

位于 src/Transformers/BooleanTransformer.php。PHP 的true/false恰好和 JavaScript 同名,所以转换几乎"零成本",保证前端拿到的是布尔类型而不是字符串"1"

3️⃣ NullTransformer —— 空值的兜底者

位于 src/Transformers/NullTransformer.php。PHP 的null对应 JS 的null,短小精悍但必不可少——否则一个 null 值就可能整条链跑空。

4️⃣ NumericTransformer —— 数字的直通车

位于 src/Transformers/NumericTransformer.php,同时认领intfloat。它做的几乎是"原样放行",因为数字在两种语言里的字面量写法一致,是整条链里最轻松的节点。

5️⃣ ObjectTransformer —— 对象的多策略专家

位于 src/Transformers/ObjectTransformer.php,是链中最"有想法"的一位,按优先级尝试三种策略:

  1. 对象有toJson()方法?直接调用(兼容 Laravel Eloquent 模型)
  2. 对象实现了JsonSerializable或是StdClass?交给json_encode()
  3. __toString()方法?退化成字符串处理

三条路都走不通,才会抛出Untransformable异常。

6️⃣ StringTransformer —— 字符串的"安全卫士"

位于 src/Transformers/StringTransformer.php。它不只是加引号,内部还有一套转义逻辑:对反斜杠、单引号、换行以及<>做替换——最后一步防止用户输入提前闭合 script 标签,规避 XSS 注入风险。这是整条链里安全含金量最高的节点。

协作全景图:一个值如何走完责任链

顺序Transformer认领条件转换结果示例
1ArrayTransformeris_array(){"id":1}
2BooleanTransformeris_bool()true/false
3NullTransformeris_null()null
4NumericTransformeris_int()is_float()42/3.14
5ObjectTransformeris_object()JSON 或转义字符串
6StringTransformeris_string()'hello'

@javascript('user', $user)为例,一次完整的调用流程:

  1. Renderer 接收参数normalizeArguments()把多种传参写法(键值对、数组、Collection)统一成key => value结构
  2. 逐个变量走链buildVariableInitialization()为每个值调用optimizeValueForJavaScript()
  3. 责任链选人getTransformer()按上表顺序询问 6 位 Transformer,命中者完成转换
  4. 拼装输出:所有window['key'] = 值;语句拼接到模板视图 src/Renderer.php 中渲染成<script>标签

如果 6 位都拒绝,异常定义在 src/Exceptions/Untransformable.php 中的Untransformable会被抛出,开发阶段立刻暴露问题,而不是让前端拿到一段坏代码。

想扩展?加一个节点就行

这正是责任链模式的红利:假设你想支持DateTime类型,只需新建一个类实现Transformer接口(canTransform判断instanceof DateTimetransform输出new Date('...')),再把它加进 Renderer 的$transformers数组——原有 6 个转换器一行都不用动。测试代码 tests/BladeTest.php 展示了如何断言转换结果,可作为扩展时的参考。

小结:小而美的设计教科书

laravel-blade-javascript 只有十几行核心代码,却把责任链模式用得恰到好处:

  • 单一职责:6 个 Transformer,一个文件一类值,各司其职
  • 统一契约canTransform+transform两方法接口,扩展零门槛
  • 链路兜底Untransformable异常让"无法转换"变得可见、可排查
  • 安全内建:StringTransformer 的转义逻辑堵住 XSS 后路

如果你正在写自己的 Laravel 包,不妨看看 src/ 下的这份源码——它证明了:经典设计模式哪怕用在一个小工具里,也能让代码结构清晰得令人愉悦 ✨

【免费下载链接】laravel-blade-javascriptA Blade directive to export variables to JavaScript项目地址: https://gitcode.com/gh_mirrors/la/laravel-blade-javascript

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 10:43:17

10分钟导入600+设备红外代码:Flipper Zero红外遥控完整实操

10分钟导入600设备红外代码&#xff1a;Flipper Zero红外遥控完整实操 【免费下载链接】Flipper Playground (and dump) of stuff I make or modify for the Flipper Zero 项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper 电视、空调、音响的遥控器总在最难找…

作者头像 李华
网站建设 2026/8/24 10:41:30

AI原生SDLC实战:基于Agent的智能软件交付循环构建指南

在实际软件工程实践中&#xff0c;软件交付循环&#xff08;SDLC&#xff09;的每个环节——需求、设计、编码、测试、部署、运维——都面临着效率瓶颈和质量挑战。传统的工具链和流程在面对快速迭代和复杂系统时&#xff0c;常常显得笨重且割裂。如今&#xff0c;以大型语言模…

作者头像 李华
网站建设 2026/8/24 10:40:21

ComfyUI脸部修复实战:MiniMax H3与T8节点应用指南

大家好&#xff0c;我是专注于AI绘画与工作流分享的技术博主。在ComfyUI的实际使用中&#xff0c;你是否遇到过这样的困扰&#xff1a;生成的人物面部细节模糊、五官扭曲&#xff0c;或者多人场景下某些角色的脸“崩”了&#xff1f;手动修复费时费力&#xff0c;效果还不稳定。…

作者头像 李华
网站建设 2026/8/24 10:39:25

C++可变参数模板:从语法到实战的范式革命

1. 从“固定”到“无限”&#xff1a;可变参数模板的范式革命在C98/03的时代&#xff0c;如果你要写一个函数来处理任意数量、任意类型的参数&#xff0c;那几乎是一场噩梦。你只能通过函数重载&#xff0c;为1个、2个、3个……参数分别写一个版本&#xff0c;这不仅代码冗余&a…

作者头像 李华