laravel Blade 指令的趣味性
首先,我们通过几个要点来解释 Blade 引擎的工作原理。
- 您选择一个 Blade 模板进行渲染。
- 引擎使用一系列正则表达式来解析和编译模板。
- 该引擎生成一个普通的 PHP 文件并将其写入磁盘(以便将其缓存以供将来渲染)。
- 包含 PHP 文件并使用输出缓冲区来捕获生成的 HTML。
该过程中最有趣的步骤是使用 RegEx 模式从模板中提取各种内容并生成适当的 PHP 代码。其他模板引擎使用更传统的标记器和解析器来处理模板,但由于 Blade 或多或少只是常规 PHP 代码的语法糖,因此它可以以更简单的方式完成工作。
这意味着您基本上总是在处理可能包含普通 PHP 代码的任意字符串。
#自定义指令
您可以编写自己的 Blade 指令。这样您就可以在指令中隐藏大量样板代码并简化 Blade 模板。
Blade::directive('example', function (string $expression) {// Logic goes here.
});
让很多新的 Laravel 开发人员感到困惑的是,自定义指令仅接收回调函数的一个参数。
假设@example()此处的指令设计为接受 2 个参数:
@example('Hello, ', 'Ryan')
经验较少的 Laravel 开发人员可能希望回调函数接收两个参数,对应于我们传递给实际指令的两个参数。
但事实并非如此。相反,我们从 Blade 模板收到一个包含文字的字符串。
Blade::directive('example', function (string $expression) {assert($expression === "'Hello, ', 'Ryan'");
});
因此,我们实际上不想在回调中编写常规 PHP 代码并返回值,而是想返回一串 PHP 代码。然后,该 PHP 代码将插入到生成的模板中以代替原始指令。
Blade::directive("example", function (string $expression) {return "<?php echo implode(' ', [{$expression}]); ?>";
});
有一些软件包可以扩展 Laravel 以支持更合乎逻辑的“在回调中接收真实参数”方法,但事实上我们这里有一个字符串意味着我们可以做一些有趣和有创意的事情。
#命名参数
自定义 Blade 指令通常会为常规 PHP 函数提供包装器。PHP 8.0 引入了“命名参数”的概念,允许您无序地将参数传递给函数,而是提供参数的名称。
function hello(string $name, string $greeting = "Hello, ")
{return $greeting . $name;
}hello(greeting: "Greetings, ", name: "Ryan");
如果我们将这个hello()函数包装在 Blade 指令中,我们实际上仍然可以使用命名参数!
Blade::directive("hello", function (string $expression) {return "<?php echo hello({$expression}); ?>";
});
@hello(greeting: "Greetings,", name: "Ryan")
由于括号之间的文本只是插入到我们的表达式中,因此命名参数会逐字传递给底层hello()函数。
很酷!
#魔法变量
大多数 Laravel 开发人员可能都曾在他们的项目中使用过“魔法变量”。最常见的两个例子可能是块$loop内可用的变量@foreach和块$message内的变量@error。
Laravel 附带一个@auth指令,允许您根据用户是否登录有条件地执行操作。这很酷,但我想发送自己的@auth指令,将当前用户作为变量注入到代码块中$user。
有趣的是,您实际上可以用自定义指令覆盖 Laravel 自己的指令,因为 Blade 编译器会先检查自定义指令。但我不建议这样做,所有这些代码纯粹是为了教育和演示目的!
Blade::directive("auth", function (string $expression) {$guard = $expression ?: "()";return "<?php if (auth()->guard{$guard}->check()): ?>" .'<?php $user = auth()->user(); ?>';
});Blade::directive("endauth", function () {return '<?php unset($user); ?>' . "<?php endif; ?>";
});
上面的代码为每个指令返回多个语句。启动和结束块if,以及创建和取消设置魔法$user变量。
该代码并非 100% 可靠,请不要在您自己的应用程序中这样做。
我们可以将指令编译成任意 PHP 代码,这为很多事情带来了一些很酷的机会。我甚至开发了几个利用这一点的软件包来缓存 Blade 代码块,甚至创建内联部分代码!
- blade 缓存指令
- blade 捕获指令
#领域特定语言
我们可以利用 Blade 指令的字符串特性的另一种方法是在 Blade 指令内编写我们自己的特定领域语言。
很多服务器端模板引擎都有“过滤器”的概念。下面是 Twig 的一个示例:
{{ names | join(',') | lower }}
是names传递给函数的变量join()。然后的输出join(',')被发送到lower,然后该操作的结果被输出到模板中。
如果我们想在 Blade 指令中执行相同操作,也许是这样的:
@filter($names | join(',') | lower)
第一步是解析指令内部的内容。为了获取所有不同的过滤器和变量,我们可以按标记拆分表达式|,删除每个部分周围的多余空格。
$parts = array_map(trim(...), explode("|", $expression));
为了简单起见,我们假设第一部分始终是一个有效的 PHP 表达式。
$subject = $parts[0];
$filters = array_slice($parts, 1);
每个过滤器都将映射到一个Closure,它接受当前的值$subject以及我们传递给过滤器的任何参数。我们需要一个地方来存储这些回调函数。
警告:您将要看到的代码包含魔法。
class Filters
{protected array $filters = [];public function __construct(protected mixed $subject){$this->addFilter("join", function (array $subject, string $glue = "") {return implode($glue, $subject);});$this->addFilter("lower", function (string $subject) {return strtolower($subject);});}public function addFilter(string $name, Closure $callback): void{$this->filters[$name] = $callback;}public function get(): mixed{return $this->subject;}public function __call(string $name, array $args){if (!isset($this->filters[$name])) {throw new Exception("Unrecognised filter [{$name}].");}$this->subject = $this->filters[$name]($this->subject, ...$args);return $this;}public function __get(string $name){return $this->{$name}();}
}
每个过滤器在实例化时都会向类注册。要实际调用过滤器,您可以调用类中不存在的方法或访问不存在的属性。
然后,Blade 指令需要将过滤器字符串转换为对象的一系列方法调用Filters。
return sprintf(<<<'PHP'
<?php echo (new \App\Filters(%s))->%s->get(); ?>
PHP,$subject,implode("\n ->", $filters)
);
将$subject传递给构造函数,然后每个过滤器将作为方法或属性链接到对象上。这会触发对象上的__call()或方法,从而运行过滤器。__get()$subject
然后在最后,->get()调用该方法来检索渲染模板中的最终值和输出。
我警告过你,这里有魔法。
因此,上面的 Blade 示例将转换为如下形式:
echo (new \App\Filters($names))->join(',')->lower->get();
通过['Ryan', 'Jane', 'John']这组过滤器将产生ryan,jane,john。
这是一些非常奇怪和古怪的东西 - 你可能永远不想在实际应用程序中使用它们 - 但无论如何,玩弄它们还是很酷的。
也许您会采纳其中的一些想法并构建一些自己的很酷的 Blade 指令,以达到有趣和神奇的目的。
相关文章:
laravel Blade 指令的趣味性
首先,我们通过几个要点来解释 Blade 引擎的工作原理。 您选择一个 Blade 模板进行渲染。引擎使用一系列正则表达式来解析和编译模板。该引擎生成一个普通的 PHP 文件并将其写入磁盘(以便将其缓存以供将来渲染)。包含 PHP 文件并使用输出缓冲…...
【面试题】等保(等级保护)的工作流程
等保(等级保护)的工作流程主要包括以下几个步骤,以下将详细分点介绍: 系统定级: 确定定级对象:根据《信息系统等级保护管理办法》和《信息系统等级保护定级指南》的要求,确定需要进行等级保护的…...
python调用麦克风和扬声器,并调用阿里云实时语音转文字
import time import queue import sounddevice as sd import numpy as np import nls import sys# 阿里云配置信息 URL "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1" TOKEN "XXXX" # 参考https://help.aliyun.com/document_detail/450255.html获…...
描述在React中集成第三方库(如Redux或React Router)的常见模式。
在React中集成第三方库,如状态管理库Redux或路由库React Router,通常遵循一些常见的模式和最佳实践。下面是一些集成这些库的步骤和模式: 集成Redux 安装Redux及相关包: 安装Redux及其中间件(如redux-thunk或redux-saga…...
JavaScript语法特性篇-空值合并运算符(??)
1、基本使用 空值合并运算符(??)英文名称为 Nullish coalescing operator,是一个逻辑运算符。 特性:当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。 const foo nul…...
rancher快照备份至S3
巧用rancher的S3快照备份功能,快速实现集群复制、集群转移、完全崩溃后的极限修复 1.进入集群管理,在对应的集群菜单后,点击编辑配置 2.选择ETCD,启用,Backup Snapshots to S3选项 并填入你的minio 3 配置成功后 手…...
ChatGPT API教程在线对接OpenAI APIKey技术教程
一、OpenAI基本库介绍 您可以通过 HTTP 请求与 API 进行交互,这可以通过任何编程语言实现。我们提供官方的 Python 绑定、官方的 Node.js 库,以及由社区维护的库。 要安装官方的 Python 绑定,请运行以下命令: pip install open…...
随心而遇,跟着感觉走
分数限制下,选好专业还是选好学校? 24年高考结束,很多学生犹豫选择专业还是好学校,我的建议是,选择好学校。 本人体验来说,电子,工地,计科,数学,工科相关的…...
LeetCode题练习与总结:只出现一次的数字--136
一、题目描述 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。 示例 1 : …...
常见的中间件都在解决什么问题?
常见的中间件都在解决什么问题 RocketMQ RocketMQ 是一款功能强大的分布式消息系统。 RocketMQ 源码地址:https://github.com/apache/rocketmq(opens new window) RocketMQ 官方网站:https://rocketmq.apache.org 什么场景下用 RocketMQ?…...
微信小程序-scroll-view实现上拉加载和下拉刷新
一.scroll-view实现上拉加载 scroll-view组件通过自身一些属性实现上拉加载的功能。 lower-threshold“100"属性表示距离底部多少px就会实现触发下拉加载的事件。 类似于在.json文件里面配置"onReachBottomDistance”: 100 bindscrolltolower"getMore"属…...
TS中interface和type的区别
在 TypeScript 中,interface 和 type 都可以用来定义对象的类型,但它们之间存在一些差异。 以下是 interface 和 type 的主要区别: 扩展(Extending): interface 可以通过 extends 关键字来扩展其他 interface。interfa…...
Hightec编译器系列之高级调试技巧精华总结
Hightec编译器系列之高级调试技巧精华总结 小T为了便于大家理解,本文的思维导图大纲如下: 之前可能很多小伙伴没有使用过Hightec编译器,大家可以参考小T之前的文章《Hightec编译器系列之白嫖就是爽》可以下载一年试用版本。 小T使用过适配英…...
【论文笔记】LoRA LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS
题目:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS 来源: ICLR 2022 模型名称: LoRA 论文链接: https://arxiv.org/abs/2106.09685 项目链接: https://github.com/microsoft/LoRA 文章目录 摘要引言问题定义现有方法的问题方法将 LORA 应用于 Transformer 实…...
【Sa-Token|4】Sa-Token微服务项目应用
若微服务数量多,如果每个服务都改动,工作量大,则可以只在网关和用户中心进行改动,也是可以实现服务之间的跳转。 这种方式可以通过在网关服务中生成和验证 Sa-Token,并将其与现有的 Token关联存储在 Redis 中。用户中心…...
鸿蒙开发系统基础能力:【@ohos.hilog (日志打印)】
日志打印 hilog日志系统,使应用/服务可以按照指定级别、标识和格式字符串输出日志内容,帮助开发者了解应用/服务的运行状态,更好地调试程序。 说明: 本模块首批接口从API version 7开始支持。后续版本的新增接口,采用…...
SpringMVC系列十: 中文乱码处理与JSON处理
文章目录 中文乱码处理自定义中文乱码过滤器Spring提供的过滤器处理中文 处理json和HttpMessageConverter<T>处理JSON-ResponseBody处理JSON-RequestBody处理JSON-注意事项和细节HttpMessageConverter<T\>文件下载-ResponseEntity<T\>作业布置 上一讲, 我们学…...
使用MyBatisPlus进行字段的自动填充
使用MyBatisPlus进行字段的自动填充 需求场景 当我们往数据库里面插入一条数据,或者是更新一条数据时,一般都需要标记创建时间create_time和更新时间update_time的值,但是如果我们每张表的每个请求,在执行sql语句的时候我们都手…...
python爬虫之aiohttp多任务异步爬虫
python爬虫之aiohttp多任务异步爬虫 爬取的flash服务如下: from flask import Flask import timeapp Flask(__name__)app.route(/bobo) def index_bobo():time.sleep(2)return Hello boboapp.route(/jay) def index_jay():time.sleep(2)return Hello jayapp.rout…...
1964springboot VUE小程序在线学习管理系统开发mysql数据库uniapp开发java编程计算机网页源码maven项目
一、源码特点 springboot VUE uniapp 小程序 在线学习管理系统是一套完善的完整信息管理类型系统,结合springboot框架uniapp和VUE完成本系统,对理解vue java编程开发语言有帮助系统采用springboot框架(MVC模式开发),…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
