<?php
namespace Illuminate\Support\Traits;
use BadMethodCallException;
use Closure;
use ReflectionClass;
use ReflectionMethod;
trait Macroable
{
/**
* 存放注册的宏方法数组
*/
protected static $macros = [];
/**
* 注册的宏方法
* @param string $name
* @param object|callable $macro
* @return void
*/
public static function macro($name, $macro)
{
static::$macros[$name] = $macro;// 方法名 => 对象
}
/**
* 混合其他对象到当前类.
* @param object $mixin
* @param bool $replace 是否替换已经存在的
* @return void
*
* @throws \ReflectionException
*/
public static function mixin($mixin, $replace = true)
{
// 通过反射得到 $mixin 对象所有 protected 和 public 方法
$methods = (new ReflectionClass($mixin))->getMethods(
ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
);
// 遍历所有方法,并把方法和对应的 添加到 static::macro 数组中
foreach ($methods as $method) {
if ($replace || ! static::hasMacro($method->name)) {
static::macro($method->name, $method->invoke($mixin)); // 类似于 $mixin->$method(), 这里要求其他返回的是个一个函数对象
}
}
}
/**
* 检测方法名是否已经注册过了
* @param string $name
* @return bool
*/
public static function hasMacro($name)
{
return isset(static::$macros[$name]);
}
/**
* 通过魔术方法,调用静态方法
* @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];
// 如果可调用对象 $macro 是匿名函数,则通过 $macro->bindTo()方法,复制 $macro 这个闭包对象,绑定 static::class 对象和类作用域
// 比如: $macro = function(){ $this->name }; $macro->bindTo($obj); $macro(); 返回的就是 $obj->name 属性
if ($macro instanceof Closure) {
$macro = $macro->bindTo(null, static::class);
}
// 最后调用并返回
return $macro(...$parameters);
}
/**
* __call 和 __callStatic 一模一样的代码
* 为啥不写一句 static::__callStatic($method, $parameters) 呢?
* @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);
}
}
标签:laravel,return,parameters,macro,Macroable,param,详解,static,method From: https://www.cnblogs.com/zbseoag/p/17525524.html