Laravel Macro 让你的代码更简洁,更具有可读性

来源:http://www.shanhubei.com/archives/2806.html

你可以把它理解成为 trait 中的一个方法,还有点和我们开发中常用助手文件中 helpers 中的方法类似,其目的是将 Laravel 的内部组件进行横向扩展以全局通用。

下面我们来看一个例子:

User 表中有一个字段是 is_vip,用来记录用户是否是 VIP,当我们在控制器中进行判断时,常规的写法是:

// UserController.php

public function getVip(Request $request)
{
    if($request->user()->is_vip)
    {
        return true;
    }
    return false;
}
 

当多个控制器都有对于 is_vip 字段进行判断的分支时,代码就会变得冗余,假如 is_vip 为真时,后续还有其他判断,那么嵌套的 if 语句就会让代码逻辑变得更复杂。

if($request->user()->is_vip)
{
    if(...)
    {
        ...
    }
}

 

 

如果我们能在 Illuminate\Http\Request 类中添加一个方法来判断请求用户 is_vip 的值就好了,Macro 就是用来做这个的,我们再来改写一下之前的方法:

public function getVip(Request $request)
{
    // 先把它暂时写在控制器中。
    Request::macro('isVip', function()
    {
        if(auth()->check()) // 先做授权判断,增加代码健壮性
        {
            return $this->user()->is_vip;  // 等同于 $request->user()->is_vip, $this 指向的是 Request 的实例。
        }
        return false;
    }

    // 这样的话控制器只有一行代码了。
    return $request->isVip(); 
}

 

 

Macro 中的 $this 指向的是被扩展方法的实例,上文中的 $this 代表的是控制器中注入的 Request 实例。

再来个例子,项目中经常需要判断字符串长度是否大于等于指定长度,通常是这样:

use Illuminate\Support\Str;
public function str()
{  
    $length = 3;
    $str1 = 'cbd';
    if(Str::length($str1) >= $length)
    {
        return true;
    }
    return false;
}
 

使用 Macro 改写后如下:

use Illuminate\Support\Str;
public function str()
{ 
    // 先把它暂时写在控制器中。
    Str::macro('lengthCheck', function(string $str1, int $length)
    {
        if(self::length($str1) >= $length)
        {
            return true;
        }
        return false;
    });

    // 这样的话控制器只有一行代码了。  
    return Str::lengthCheck($str1, $length);
}
 

好了,到这里已经对 Macro 有一个基本的概念了,鼠标宏都用过吧?它不就是鼠标功能的一个扩展?鼠标本身没有连点功能,但是它提供了一个接口来让我们自定义编程,从而实现我们想要的功能。

下面我们还需要让 Macro 在框架加载时一同载入,从而实现全局调用,你可以将它写在 AppServiceProvider.php 中,如果数量不多的话,这个视情况决定。

本例中我们来创建一个 Provider,来统一将这些 Macro 放在一起。

php artisan make:provider MacrosServiceProvider
 

把上面两个 Macro 放入到 MacrosServiceProvider

<?php

namespace App\Providers;

use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;

class MacrosServiceProvider extends ServiceProvider
{  
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        // 判断用户是否是 VIP
        Request::macro('isVip', function(){
            if(auth()->check())
            {
                return $this->user()->is_vip;
            }
            return false;
        });

        // 判断字符串是否大于等于给定长度
        Str::macro('lengthCheck', function(string $str1, int $length)
        {
            if(static::length($str1) >= $length)
            {
                return true;
            }
            return false;
        });

    }
}

在 app.php 中加载它

'providers' => [
    ...
    \App\Providers\MacrosServiceProvider::class,
];

在开发中多考虑使用 Macro 来让你的代码更具有可读性和复用性,希望本文对你有帮助。

最后说一下,哪些 Laravel 的组件可以使用 Macro 扩展:

  • Illuminate\Auth\RequestGuard
  • Illuminate\Auth\SessionGuard
  • Illuminate\Cache\Repository
  • Illuminate\Console\Command
  • Illuminate\Console\Scheduling\Event
  • Illuminate\Cookie\CookieJar
  • Illuminate\Database\Eloquent\FactoryBuilder
  • Illuminate\Database\Eloquent\Relations\Relation
  • Illuminate\Database\Grammar
  • Illuminate\Database\Query\Builder
  • Illuminate\Database\Schema\Blueprint
  • Illuminate\Filesystem\Filesystem
  • Illuminate\Foundation\Testing\TestResponse
  • Illuminate\Http\JsonResponse
  • Illuminate\Http\RedirectResponse
  • Illuminate\Http\Request
  • Illuminate\Http\Response
  • Illuminate\Http\UploadedFile
  • Illuminate\Mail\Mailer
  • Illuminate\Routing\PendingResourceRegistration
  • Illuminate\Routing\Redirector
  • Illuminate\Routing\ResponseFactory
  • Illuminate\Routing\Route
  • Illuminate\Routing\Router
  • Illuminate\Routing\UrlGenerator
  • Illuminate\Support\Arr
  • Illuminate\Support\Collection
  • Illuminate\Support\LazyCollection
  • Illuminate\Support\Str
  • Illuminate\Support\Testing\Fakes\NotificationFake
  • Illuminate\Translation\Translator
  • Illuminate\Validation\Rule
  • Illuminate\View\Factory
  • Illuminate\View\View

附言:
关于 PHPSTORM IDE 没有 Macro 提示的问题解决方法:

安装 barryvdh/laravel-ide-helper 组件

composer require --dev barryvdh/laravel-ide-helper
 

跟着文档一步一步走就行了,注意文档中有一句话,如果要使用代码提示的话,必须根据文档中的要求来写:

为 Macro 和 Mixin 自动生成 PHPDoc

这个包可以为 Macro 和 Mixin 生成 PHPDocs,它们将被添加到 _ide_helper.php 文件中。

但这仅在您在声明宏时使用类型提示时才有效。

Str::macro('concat', function(string $str1, string $str2) : string {
    return $str1 . $str2;
});

 

 
posted @ 2023-10-17 17:15  珊瑚贝博客  阅读(102)  评论(0编辑  收藏  举报