使用 Macro 讓你的程式碼更簡潔,更具有可讀性

MArtian發表於2022-03-24

Macro 是 Laravel 框架的一個強大功能。 它可以向 Laravel 的內部元件新增自定義功能。

你可以把它理解成為 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

更多參考 :
教程:如何利用 macro 方法來擴充套件 Laravel 的基礎類的功能

翻譯:神奇的 Laravel 巨集指令(Macro)


附言:
關於 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;
});
本作品採用《CC 協議》,轉載必須註明作者和本文連結
我從未見過一個早起、勤奮、謹慎,誠實的人抱怨命運。

相關文章