惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
TaoSecurity Blog
TaoSecurity Blog
Recorded Future
Recorded Future
WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
A
Arctic Wolf
Last Week in AI
Last Week in AI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CERT Recently Published Vulnerability Notes
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 聂微东
有赞技术团队
有赞技术团队
GbyAI
GbyAI
博客园 - Franky
D
Docker
H
Hackread – Cybersecurity News, Data Breaches, AI and More
P
Privacy & Cybersecurity Law Blog
AWS News Blog
AWS News Blog
T
The Blog of Author Tim Ferriss
G
GRAHAM CLULEY
宝玉的分享
宝玉的分享
Vercel News
Vercel News
T
Tailwind CSS Blog
P
Palo Alto Networks Blog
Latest news
Latest news
阮一峰的网络日志
阮一峰的网络日志
S
Securelist
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Check Point Blog
Google DeepMind News
Google DeepMind News
The Cloudflare Blog
A
About on SuperTechFans
T
Threat Research - Cisco Blogs
Jina AI
Jina AI
The Hacker News
The Hacker News
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Security Affairs
V
Visual Studio Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
J
Java Code Geeks
Cyberwarzone
Cyberwarzone
K
Kaspersky official blog
IT之家
IT之家
Project Zero
Project Zero
博客园 - 【当耐特】
Scott Helme
Scott Helme
罗磊的独立博客
人人都是产品经理
人人都是产品经理

mafeifan 的编程技术分享

mafengwo-mp3-downloader | mafeifan 的编程技术分享 示例页面 | mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 查看 default namespace 下的 default service account名称 mafeifan 的编程技术分享 检查日志 | mafeifan 的编程技术分享 bridge fdb show dev flannel.1 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 数据收集原理分析 | mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 几种方法 | mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 check the export on the very top of this document so we can use $do mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 运维自动化之ANSIBLE | mafeifan 的编程技术分享 延伸 -- 关于前端路由 xdebug 3 和 2 的区别
mafeifan 的编程技术分享
2026-01-16 · via mafeifan 的编程技术分享

理解Laravel中的 Macroable

计算机科学里的宏(Macro),是一种批量处理的称谓。 比如有些重复的动作,可以打包记录为一个宏,给宏名字,调用这个宏,就等于执行这一系列动作了。

下面看下Laravel中宏的源码实现

源码分析 ​

php

<?php
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
     * @param  bool  $replace
     * @return void
     *
     * @throws \ReflectionException
     */
    public static function mixin($mixin, $replace = true)
    {
        // 通过反射获取该对象中所有公开和受保护的方法
        $methods = (new ReflectionClass($mixin))->getMethods(
            ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
        );

        foreach ($methods as $method) {
            if ($replace || ! static::hasMacro($method->name)) {
                // 设置方法可访问,因为受保护的不能在外部调用
                $method->setAccessible(true);
                // 调用 macro 方法批量创建宏指令
                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) {
            return call_user_func_array(  ($macro, null, static::class), $parameters);
        }

        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) {
            return call_user_func_array($macro->bindTo($this, static::class), $parameters);
        }

        return $macro(...$parameters);
    }
}

class Father
{
    public function say()
    {
        return function () {
            echo 'say';
        };
    }

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

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

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

class Child
{
    use Macroable;
}

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

$child = new Child;
// 输出:say
$child->say();
// 输出:show
$child->show();
// 输出:eat
$child->eat();
// 因为 Macroable 加了 __callStatic 支持静态调用
$child::eat();
// 这样调用会报错,因为test返回的不是闭包
$child->test();

Laravel中使用 ​

在Laravel中,很多类都实现了Macroable,比如下列(in Laravel5.4)

php

Illuminate\Database\Query\Builder
Illuminate\Database\Eloquent\Builder
Illuminate\Database\Eloquent\Relations\Relation
Illuminate\Http\Request
Illuminate\Http\RedirectResponse
Illuminate\Http\UploadedFile
Illuminate\Routing\Router
Illuminate\Routing\ResponseFactory
Illuminate\Routing\UrlGenerator
Illuminate\Support\Arr
Illuminate\Support\Str
Illuminate\Support\Collection
Illuminate\Cache\Repository
Illuminate\Console\Scheduling\Event
Illuminate\Filesystem\Filesystem
Illuminate\Foundation\Testing\TestResponse
Illuminate\Translation\Translator
Illuminate\Validation\Rule

我们就可以这么搞

php

use Illuminate\Support\Collection;

// 定义一个宏
Collection::macro('someMethod', function ($arg1 = 1, $arg2 = 1) {
    // count 是 collection对象内置的方法
    return $this->count() + $arg1 + $arg2;
});

// 调用宏
// 我们只是向类中添加了一个以前不存在的方法,而无需接触任何源文件。

$coll = new Collection([1, 2, 3]);
echo $coll->someMethod(1, 2);

使用macro往一个类中添加新方法

php

$macroableClass = new class() {
    use Macroable;
};

$macroableClass::macro('concatenate', function(... $strings) {
   return implode('-', $strings);
};

$macroableClass->concatenate('one', 'two', 'three'); // returns 'one-two-three'

使用mixin方法往一个类追加多个方法

php

$mixin = new class() {
    public function mixinMethod()
    {
       return function() {
          return 'mixinMethod';
       };
    }
    
    public function anotherMixinMethod()
    {
       return function() {
          return 'anotherMixinMethod';
       };
    }
};

$macroableClass->mixin($mixin);

$macroableClass->mixinMethod() // returns 'mixinMethod';

$macroableClass->anotherMixinMethod() // returns 'anotherMixinMethod';

也就是说,我们可以通过宏扩展原有的功能,看这个例子,往Query Build中添加list方法

把宏定义添加到AppServiceProvider文件的boot方法中,这样可以在全局使用啦

php

Collection::macro('firstNth', function($take) {
    // 加 static 确保返回 collection 类型
    return new static(array_slice($this->item, 0, $take));
});

参考 ​

https://asklagbox.com/blog/laravel-macros

https://learnku.com/articles/35970

https://github.com/spatie/macroable