Laravel Macroable
一、预备知识
Laravel Macroable 的使用需要对php闭包的相关知识有所了解,可以参看文档 php 闭包
二、代码分析
Laravel Macroable 源码对应 \Illuminate\Support\Traits\Macroable 这个trait 文件,这里将其代码剥离出来单独运行、测试,以便研究。
其源码如下
// Macroable.php
<?phptrait Macroable {/*** The registered string macros.* 变量是一个数组* 键为方法名,值为闭包,对应此方法的具体实现* @var array*/protected static $macros = [];/*** Register a custom macro.* 注册方法,保存到 静态变量 $macros 中* @param string $name* @param object|callable $macro* @return void*/public static function macro($name, $macro){static::$macros[$name] = $macro;}/*** Mix another object into the class.** @param object $mixin* @param bool $replace 如果方法已经存在是否覆盖,true表示覆盖,false表示不覆盖,* true 意味着生效的是第一次注册的闭包,false 则意味着生效的是最后一次注册的闭包* @return void** @throws \ReflectionException*/public static function mixin($mixin, $replace = true){// 获取 $mixin 对象的所有公有和保护方法$methods = (new ReflectionClass($mixin))->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);foreach ($methods as $method) {// 依次激活该对象的每个方法,并将每个方法返回的匿名函数注册到 $macros 中if ($replace || ! static::hasMacro($method->name)) {$method->setAccessible(true);static::macro($method->name, $method->invoke($mixin));}}}/*** Checks if macro is registered.* 判断方法是否存在* @param string $name* @return bool*/public static function hasMacro($name){return isset(static::$macros[$name]);}/*** Dynamically handle calls to the class.** @param string $method* @param array $parameters* @return mixed** @throws \BadMethodCallException*/public static function __callStatic($method, $parameters){if (! static::hasMacro($method)) {// 如果方法未提前注册,则抛出异常throw new BadMethodCallException(sprintf('Method %s::%s does not exist.', static::class, $method));}// 找到方法名对应的闭包$macro = static::$macros[$method];if ($macro instanceof Closure) {// 绑定闭包到类$macro = $macro->bindTo(null, static::class);}// 调用闭包return $macro(...$parameters);}/*** Dynamically handle calls to the class.** @param string $method* @param array $parameters* @return mixed** @throws \BadMethodCallException*/public function __call($method, $parameters){if (! static::hasMacro($method)) {// 如果方法未提前注册,则抛出异常throw new BadMethodCallException(sprintf('Method %s::%s does not exist.', static::class, $method));}// 找到方法名对应的闭包$macro = static::$macros[$method];if ($macro instanceof Closure) {// 绑定闭包到当前对象$macro = $macro->bindTo($this, static::class);}// 调用闭包return $macro(...$parameters);}
}
其中 macro、hasMacro 方法比较简单,重点是 __callStatic、__call 和 mixin 方法,下面分别进行分析,
2.1 __callStatic 和 __call
先看一个用法示例
require __DIR__.DIRECTORY_SEPARATOR.'Macroable.php';class MacroTest
{// 引入 Macroable traituse Macroable;
}// 注册一个名为 addedJoin 的方法,
// 作用是把多个字符串拼成一个字符串,字符串之间用 '-' 隔开
MacroTest::macro('addedJoin', function(...$string){return implode('-', $string);
});// 注册后,可以以静态方法的方式调用 addedJoin 方法
// 好像 MacroTest 类增加了一个静态方法
echo MacroTest::addedJoin('a','b','c'),"\n";// MacroTest 对象也可以调用 addedJoin 方法
// 好像 MacroTest 类增加了一个普通的public 成员函数
$obj = new MacroTest();
echo $obj->addedJoin('a','b','c'),"\n";
必须先注册方法的闭包,否则会报异常,整个实现实际上归功于 Macroable 中定义的两个魔术方法:__callStatic 和 __call,PHP中如果调用的方法不存在,会触发调用相应的魔术方法,静态方法对应__callStatic方法,普通方法对应 __call方法。阅读代码会发现 Macroable 中两个魔术方法的实现是类似的,都是先根据方法名找到注册的闭包,然后进行绑定,最后调用绑定后的闭包。
虽然注册的方法同时支持静态和非静态两种调用方式,但具体应该怎么调用实际上取决于闭包的具体实现,如果注册的方法使用了 $this 那么显然只能通过类对象调用。
2.2 mixin
mixin 用于一次性把指定对象的所有公有和保护方法加到另一个类中,需要注意的是其中的注册语句
static::macro($method->name, $method->invoke($mixin))
$method->invoke($mixin)
这一句意味着注册是调用了对象相应方法的返回值,这意味着被添加的对象所有的公有、保护方法都需要返回一个闭包,这其实是一个很大的限制,因为这意味着公有的构造函数和返回对象本身的方法都不能有,也就是这个类不能产生对象,只能包含静态成员和返回闭包的接口。
class ObjNotOk
{public function notReturnClosure(... $string){// 这样的类对象不能用于mixin方法加到另一个类return implode('-', $string);}
}
下面是可用于mixin的类示例
<?php
require __DIR__ . DIRECTORY_SEPARATOR . 'Macroable.php';class MacroTest
{use Macroable;
}class Str
{public function join(){return function (...$string) {return implode('-', $string);};}public function split(){return function (string $string) {return explode('-', $string);};}
}MacroTest::mixin(new Str(100), true);echo MacroTest::join('a', 'b', 'c'), "\n";
print_r(MacroTest::split('a-b-c'));
参考
https://blog.csdn.net/larance001/article/details/121479499
Laravel Macroable相关推荐
- Laravel 中简约而不简单的 Macroable 宏指令
百度百科的定义: 计算机科学里的宏(Macro),是一种批量处理的称谓.一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是 ...
- 【社交系统ThinkSNS+研发日记】Laravel Model 利用 Macroable 为数据模型添加宏能
2019独角兽企业重金招聘Python工程师标准>>> 什么是ThinkSNS ? ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研 ...
- Laravel 中简约而不简单的 Macroable 宏指令 1
百度百科的定义: 计算机科学里的宏(Macro),是一种批量处理的称谓.一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是 ...
- Laravel Model 利用 Macroable 为数据模型添加宏能力
[摘要]简单的说一下宏能力,这个类是 IlluminateSupportTraitsMacroable 其中利用重载实现了可以定义宏的功能,即通过 macro 静态方法添加回调,并定义一个名字.利用 ...
- 个人在 laravel 开发中使用到的一些技巧(持续更新)
1.更高效率地查询:使用批量查询代替 foreach 查询(多次 io 操作转换为一次 io操作) 如果想要查看更详尽的介绍,可以看看这篇文章 什么是 N+1 问题,以及如何解决 Laravel 的 ...
- 如何使用 Laravel Collections 类编写神级代码
本文首发于 如何使用 Laravel Collections 类编写神级代码,转载请注明出处. Laravel 提供了一些超赞的组件,在我看来,它是目前所有 Web 框架中提供组件支持最好的一个.它不 ...
- php macro,如何利用 macro 方法来扩展 Laravel 的基础类的功能
在一般编程中,我们要扩展一个基础类,我们需要进行继承才能扩充.然而Laravel利用PHP的特性,编写了一套叫做Macroable的Traits,这样,凡是使用Macroable的类,都是可以使用这个 ...
- Laravel 的 Auth::attempt () 初探及修改 bcrypt 验证为 MD5
如果你在使用Laravel的话,用户的代码只需要一行代码就可以搞定 if (Auth::attempt(['email' => $email, 'password' => $passwor ...
- Laravel集成Maatwebsite-Laravel-Excel最新版本v3
github:https://github.com/Maatwebsite/Laravel-Excel 参考文档:https://docs.laravel-excel.com/3.1/getting- ...
最新文章
- 金融数据分析(四)-------矩,偏度,峰度
- async [ə'zɪŋk] 函数
- string 与char *的区别
- 学生管理系统——基于双向循环链表
- 用memcached-session-manager实现Tomcat集群
- Django 第八课 3.【MySQL问题】
- tocmat linux搭建测试环境,Apache+Tomcat 环境搭建(JK部署过程)
- 影响页面布局的css属性,6 和页面布局有关的CSS属性(三)
- Intellij Idea选中内容后Backspace删除无法使用,Ctrl+c/Ctrl+v/Ctrl+s/Ctrl+d等等快捷键无法使用的问题的解决
- 保证服务4个9的可用性的核心思路
- solidworks电气元件3d库_60套机械设计三维选型软件 非标自动化 电气选型SolidWorks标准件...
- opencv图片保存0字节_Opencv中IplImage存储方式介绍
- 人教版初中数学七年级上册“阅读与思考”《数字1与字母X的对话》教学设计
- Matlab数据线性化
- 分节符是什么?怎么利用分节符设置某一页文档的页眉页脚?
- C++ SLT中的容器学习与函数谓词
- ssdt函数索引号_获得SSDT函数名和索引号的代码
- 读不完《程序员修炼之道》,至少可以读完这70条
- 艾美捷SequENZ测序级改造型胰蛋白酶用途和技术说明
- w500 安装mac
热门文章
- 用AI生成的一张美女老师图,大家一定要仔细的看她眼睛,是否发现了什么?
- 2021-7-8 山东大学软件学院暑期项目实训日志-第二周 03
- ati jti jwt 和_JWT 详解
- 链家网站系统测试设计与实现_kaic
- TWO DAY | WEB安全之OWASP TOP10漏洞
- wmi java_Java用wmi4j远程管理Windows服务
- Pocket Yoga瑜伽专注自律,一起变美吧!
- 如何借鉴一个优秀的网站
- 【木头Cocos2d-x 029】Lua篇(第04章):来点高难度的,获取Lua表结构数据
- JavaWeb过滤器(Filter)详解,是时候该把过滤器彻底搞懂了(万字说明)