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 的基礎類的功能
附言:
關於 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 協議》,轉載必須註明作者和本文連結