一、预备知识

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相关推荐

  1. Laravel 中简约而不简单的 Macroable 宏指令

    百度百科的定义: 计算机科学里的宏(Macro),是一种批量处理的称谓.一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是 ...

  2. 【社交系统ThinkSNS+研发日记】Laravel Model 利用 Macroable 为数据模型添加宏能

    2019独角兽企业重金招聘Python工程师标准>>> 什么是ThinkSNS ? ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研 ...

  3. Laravel 中简约而不简单的 Macroable 宏指令 1

    百度百科的定义: 计算机科学里的宏(Macro),是一种批量处理的称谓.一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是 ...

  4. Laravel Model 利用 Macroable 为数据模型添加宏能力

    [摘要]简单的说一下宏能力,这个类是 IlluminateSupportTraitsMacroable 其中利用重载实现了可以定义宏的功能,即通过 macro 静态方法添加回调,并定义一个名字.利用 ...

  5. 个人在 laravel 开发中使用到的一些技巧(持续更新)

    1.更高效率地查询:使用批量查询代替 foreach 查询(多次 io 操作转换为一次 io操作) 如果想要查看更详尽的介绍,可以看看这篇文章 什么是 N+1 问题,以及如何解决 Laravel 的 ...

  6. 如何使用 Laravel Collections 类编写神级代码

    本文首发于 如何使用 Laravel Collections 类编写神级代码,转载请注明出处. Laravel 提供了一些超赞的组件,在我看来,它是目前所有 Web 框架中提供组件支持最好的一个.它不 ...

  7. php macro,如何利用 macro 方法来扩展 Laravel 的基础类的功能

    在一般编程中,我们要扩展一个基础类,我们需要进行继承才能扩充.然而Laravel利用PHP的特性,编写了一套叫做Macroable的Traits,这样,凡是使用Macroable的类,都是可以使用这个 ...

  8. Laravel 的 Auth::attempt () 初探及修改 bcrypt 验证为 MD5

    如果你在使用Laravel的话,用户的代码只需要一行代码就可以搞定 if (Auth::attempt(['email' => $email, 'password' => $passwor ...

  9. Laravel集成Maatwebsite-Laravel-Excel最新版本v3

    github:https://github.com/Maatwebsite/Laravel-Excel 参考文档:https://docs.laravel-excel.com/3.1/getting- ...

最新文章

  1. 金融数据分析(四)-------矩,偏度,峰度
  2. async [ə'zɪŋk] 函数
  3. string 与char *的区别
  4. 学生管理系统——基于双向循环链表
  5. 用memcached-session-manager实现Tomcat集群
  6. Django 第八课 3.【MySQL问题】
  7. tocmat linux搭建测试环境,Apache+Tomcat 环境搭建(JK部署过程)
  8. 影响页面布局的css属性,6 和页面布局有关的CSS属性(三)
  9. Intellij Idea选中内容后Backspace删除无法使用,Ctrl+c/Ctrl+v/Ctrl+s/Ctrl+d等等快捷键无法使用的问题的解决
  10. 保证服务4个9的可用性的核心思路
  11. solidworks电气元件3d库_60套机械设计三维选型软件 非标自动化 电气选型SolidWorks标准件...
  12. opencv图片保存0字节_Opencv中IplImage存储方式介绍
  13. 人教版初中数学七年级上册“阅读与思考”《数字1与字母X的对话》教学设计
  14. Matlab数据线性化
  15. 分节符是什么?怎么利用分节符设置某一页文档的页眉页脚?
  16. C++ SLT中的容器学习与函数谓词
  17. ssdt函数索引号_获得SSDT函数名和索引号的代码
  18. 读不完《程序员修炼之道》,至少可以读完这70条
  19. 艾美捷SequENZ测序级改造型胰蛋白酶用途和技术说明
  20. w500 安装mac

热门文章

  1. 用AI生成的一张美女老师图,大家一定要仔细的看她眼睛,是否发现了什么?
  2. 2021-7-8 山东大学软件学院暑期项目实训日志-第二周 03
  3. ati jti jwt 和_JWT 详解
  4. 链家网站系统测试设计与实现_kaic
  5. TWO DAY | WEB安全之OWASP TOP10漏洞
  6. wmi java_Java用wmi4j远程管理Windows服务
  7. Pocket Yoga瑜伽专注自律,一起变美吧!
  8. 如何借鉴一个优秀的网站
  9. 【木头Cocos2d-x 029】Lua篇(第04章):来点高难度的,获取Lua表结构数据
  10. JavaWeb过滤器(Filter)详解,是时候该把过滤器彻底搞懂了(万字说明)