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

栏目: 编程语言 · PHP · 发布时间: 7年前

内容简介:百度百科的定义: 计算机科学里的宏(Macro),是一种批量处理的称谓。一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串)。这种替换在预编译时进行,称作宏展开。很简单的代码,根据参数的注释,在上面的代码可以看出

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

  • 我一开始接触宏是在大学上计算机基础课程时,老师讲 office 时说的。那时老师介绍宏操作时没太在意,只记得这一操作很强大,它能使日常工作变得更容易。
  • 今天我们讲讲 Laravel 中的宏操作

首先完整的源码

<?php

namespace Illuminate\Support\Traits;

use Closure;
use ReflectionClass;
use ReflectionMethod;
use BadMethodCallException;

trait Macroable
{
    /**
     * The registered string macros.
     *
     * @var array
     */
    protected static $macros = [];

    /**
     * Register a custom macro.
     *
     * @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
     * @return void
     */
    public static function mixin($mixin)
    {
        $methods = (new ReflectionClass($mixin))->getMethods(
            ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
        );

        foreach ($methods as $method) {
            $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("Method {$method} does not exist.");
        }

        if (static::$macros[$method] instanceof Closure) {
            return call_user_func_array(Closure::bind(static::$macros[$method], null, static::class), $parameters);
        }

        return call_user_func_array(static::$macros[$method], $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("Method {$method} does not exist.");
        }

        $macro = static::$macros[$method];

        if ($macro instanceof Closure) {
            return call_user_func_array($macro->bindTo($this, static::class), $parameters);
        }

        return call_user_func_array($macro, $parameters);
    }
}

复制代码
  • Macroable::macro 方法
public static function macro($name, $macro)
{
	static::$macros[$name] = $macro;
}
复制代码

很简单的代码,根据参数的注释, $macro 可以传一个闭包或者对象,之所以可以传对象,多亏了 PHP 中的魔术方法

class Father
{
    // 通过增加魔术方法**__invoke**我们就可以把对象当做闭包来使用了。
	public function __invoke()
    {
        echo __CLASS__;
    }
}

class Child
{
	use \Illuminate\Support\Traits\Macroable;
}

// 增加了宏指令之后,我们就能调用 Child 对象中不存在的方法了
Child::macro('show', new Father);
// 输出:Father
(new Child)->show();
复制代码
  • Macroable::mixin 方法 这个方法是把一个对象的方法的返回结果注入到原对象中
public static function mixin($mixin)
{
    // 通过反射获取该对象中所有公开和受保护的方法
	$methods = (new ReflectionClass($mixin))->getMethods(
		ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
	);

	foreach ($methods as $method) {
	    // 设置方法可访问,因为受保护的不能在外部调用
		$method->setAccessible(true);
		
		// 调用 macro 方法批量创建宏指令
		static::macro($method->name, $method->invoke($mixin));
	}
}

// 实际使用
class Father
{
    public function say()
    {
        return function () {
            echo 'say';
        };
    }

    public function show()
    {
        return function () {
            echo 'show';
        };
    }

    protected function eat()
    {
        return function () {
            echo 'eat';
        };
    }
}

class Child
{
    use \Illuminate\Support\Traits\Macroable;
}

// 批量绑定宏指令
Child::mixin(new Father);

$child = new Child;
// 输出:say
$child->say();
// 输出:show
$child->show();
// 输出:eat
$child->eat();
复制代码

在上面的代码可以看出 mixin 可以将一个类的方法绑定到宏类中。需要注意的就是,方法必须是返回一个闭包类型。

  • Macroable::hasMacro 方法
public static function hasMacro($name)
{
	return isset(static::$macros[$name]);
}
复制代码

这个方法就比较简单没什么复杂可言,就判断是否存在宏指令。通常是使用宏指令之前判断一下。

  • Macroable::__callMacroable::__callStatic 方法 正是由于这两个方法,我们才能进行宏操作,两个方法除了执行方式不同,代码大同小异。这里讲一下 __call
public function __call($method, $parameters)
{
    // 如果不存在这个宏指令,直接抛出异常
	if (! static::hasMacro($method)) {
		throw new BadMethodCallException("Method {$method} does not exist.");
	}

    // 得到存储的宏指令
	$macro = static::$macros[$method];

	// 闭包做一点点特殊的处理
	if ($macro instanceof Closure) {
		return call_user_func_array($macro->bindTo($this, static::class), $parameters);
	}

	// 不是闭包,比如对象的时候,直接通过这种方法运行,但是要确保对象有`__invoke`方法
	return call_user_func_array($macro, $parameters);
}


class Child
{
    use \Illuminate\Support\Traits\Macroable;

    protected $name = 'father';
}

// 闭包的特殊处理,需要做的就是绑定 $this, 如
Child::macro('show', function () {
    echo $this->name;
});

// 输出:father
(new Child)->show();
复制代码

在上面的操作中我们绑定宏时,在闭包中可以通过 $this 来调用 Child 的属性,是因为在 __call 方法中我们使用 Closure::bindTo 方法。

官网对 Closure::bindTo 的解释:复制当前闭包对象,绑定指定的$this对象和类作用域。

Laravel 中对类增加宏指令

Laravel中很多类都使用了宏这个 trait

Laravel 中简约而不简单的 Macroable 宏指令
比如 Illuminate\Filesystem\Filesystem::class

,我们想为这个类增加一个方法,但不会动到里面的代码。

  1. 我们只需要到 App\Providers\AppServiceProvider::register 方法增加宏指令(你也可以专门新建一个服务提供者专门处理)
    Laravel 中简约而不简单的 Macroable 宏指令
  2. 然后增加一条测试路由,测试我们新增加的方法
    Laravel 中简约而不简单的 Macroable 宏指令
  3. 然后打开浏览器运行,你就会发现,我们的代码可以正常的运行了并输出结果了

原文地址


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP and MySQL Web Development (3rd Edition) (Developer's Library

PHP and MySQL Web Development (3rd Edition) (Developer's Library

Luke Welling、Laura Thomson / Sams / 2004-09-29 / USD 49.99

We've taken the best and made it even better. The third edition of the best-selling PHP and MySQL Web Development has been updated to include material and code on MySQL 5, PHP 5 and on PHPs object mod......一起来看看 《PHP and MySQL Web Development (3rd Edition) (Developer's Library》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具