你可以把它理解成为 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; });