神奇的 Laravel 宏指令(Macro)

Laravel

可曾有过想要的一项功能在Laravel中,但它又不是真实存在的?让我来给你介绍一下Laravel宏指令。宏指令允许你添加自定义功能到Laravel的内部组件里去。

让我们以一个简单的Request门面方法为例。

Request::macro('introduce', function ($name) {
    echo 'Hello ' . $name . '!';
});

Request::introduce('Caleb'); // outputs "Hello Caleb!"

一个更加实用的Request宏指令是用于检测当前的TLD(顶级域:.com,.net,.org,.etc…)。

Request::macro('tldIs', function ($tld) {
    return Str::is('*.' . $tld, $this->root());
});

Request::tldIs('com') // returns true for app.com
Request::tldIs('dev') // returns false for app.com

你会注意到Laravel自动绑定$thisRequest的上下文中,而不是在一个已经定义宏的类里。比如:

class AppServiceProvider
{
    public function boot()
    {
        Request::macro('context', function () {
            return get_class($this);
        }
    }
...

Request::context(); 
// returns 'Illuminate\Http\Request'
// instead of 'App\AppServiceProvider'

让我们看一个更高级的示例。此宏有条件地基于当前TLD在模型上添加一个where语句。

Builder::macro('whenTldMatches', function($tld, $callback) {
    if (Request::tldIs($tld)) {
        call_user_func($callback->bindTo($this));
    }
    return $this;
});

SomeModel::whenTldMatches('org', function () {
    $this->where('id', '>', 5);
})->get();

// applies ->where() 在 app.org 上应用,而不在 app.com 上应用

我们应该在哪里定义它们?

服务提供者是为您的应用程序定义宏的好地方。App\Providers\AppServiceProvider boot()是一个很好的注入点,但是它很快就变得臃肿。
下一步是创建一个 App\Providers\MacrosServiceProvider 并注册在 config/app.php里。 如果某个宏与之相关,我可能会创建一个App\Providers\TldAwareServiceProvider来容纳所有与TLD相关的宏。

哪些组件是 Macroable

宏可以再任何具有Macroable特性的类上定义。下面是一个Macroable的门面和类的列表

门面

  • Cache
  • File
  • Lang
  • Request
  • Response
  • Route
  • URL

Illuminate Classes

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

动手

如果您发现自己在整个系统中对Laravel组件重复执行逻辑,请考虑使用宏以实现更好的表达和重用。相信我,非常馋。

祝您好运!

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://tighten.co/blog/the-magic-of-lar...

译文地址:https://learnku.com/laravel/t/40920

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 3

我之前尝试学习c语言的时候,就学习过宏。其实在一部分软件使用,或者书籍中也看到过宏定义、宏扩展的字段。
我个人的理解就是,把指定的语句在编译时替换
比如我定义了一个user_age_int的类型,实际上该类型不存在,在编译的时候自动替换成为无符号的整数型。

好处之一就在于可以让代码更加语义化,写起来有劲儿,读起来畅通。

4年前 评论

很不错,简洁清晰

1年前 评论

有办法给Model也增加 Macroable 么?

10个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!