Laravel 服务提供者:它们是什么以及如何使用它们
发布于 作者: PovilasKorop
对于那些没有积极使用 Laravel 服务提供者的开发者来说,它是一个神秘的“术语”:它们实际上“提供”什么“服务”,以及它是如何工作的?我将在本文中解释它。
默认 Laravel 服务提供者
让我们从 Laravel 中包含的默认服务提供者开始,它们都在 app/Providers
文件夹中
- AppServiceProvider
- AuthServiceProvider
- BroadcastServiceProvider
- EventServiceProvider
- RouteServiceProvider
它们都是 PHP 类,每个类都与其主题相关:通用“app”、Auth、广播、事件和路由。但它们都有一个共同点:boot()
方法。
在该方法中,您可以编写与这些部分之一相关的任何代码:auth、事件、路由等。换句话说,服务提供者只是用于注册一些全局功能的类。
它们被分离为“提供者”,因为它们在应用程序生命周期中非常早地执行,因此在执行脚本到达模型或控制器之前,在服务提供者中注册一些全局功能很方便。
RouteServiceProvider 中的功能最多,让我们看一下它的代码
class RouteServiceProvider extends ServiceProvider{ public const HOME = '/dashboard'; public function boot() { $this->configureRateLimiting(); $this->routes(function () { Route::prefix('api') ->middleware('api') ->group(base_path('routes/api.php')); Route::middleware('web') ->group(base_path('routes/web.php')); }); } protected function configureRateLimiting() { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); }); }}
这是配置路由文件的地方,默认情况下包括 routes/web.php
和 routes/api.php
。注意,对于 API,还有不同的配置:所有路由的端点前缀 /api
和中间件 api
。
您可以根据自己的需要编辑这些服务提供者,它们不在 /vendor
文件夹中。当您有很多路由并且想要在自定义文件中分离它们时,通常会对该文件进行自定义。您创建 routes/auth.php
并将路由放在那里,然后您在 RouteServiceProvider
的 boot()
方法中“启用”该文件,只需添加第三句话即可
`Route::middleware('web') // or maybe you want another middleware? ->group(base_path('routes/auth.php'));
其他默认服务提供者具有其他功能,您可以自己分析它们。除了 AppServiceProvider
之外,它是空的,就像一个占位符,供我们添加与某些全局应用程序设置相关的任何代码。
在 AppServiceProvider
中添加代码的一个流行例子是关于 在开发期间禁用 Eloquent 的延迟加载。为此,您只需要 添加两行 到 boot()
方法中
// app/Providers/AppServiceProvider.phpuse Illuminate\Database\Eloquent\Model; public function boot(){ Model::preventLazyLoading(! $this->app->isProduction());}
如果某些关系模型没有被预加载,这将抛出异常,这会导致所谓的 N+1 查询问题,从而影响性能。
何时执行服务提供者?
如果您查看关于 请求生命周期的官方文档,这些是在最开始执行的东西
- public/index.php
- bootstrap/app.php
- app/Http/Kernel.php 及其中间件
- 服务提供者:这正是我们本文的主题
加载哪些提供者?它在 config/app.php
数组中定义
return [ // ... other configuration values 'providers' => [ /* * Laravel Framework Service Providers... */ Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, // ... other framework providers from /vendor Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, /* * PUBLIC Service Providers - the ones we mentioned above */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, ], ];
如您所见,有一个来自 /vendor
文件夹的非公共服务提供者列表,您不应该触碰/编辑它们。我们感兴趣的是底部的那些,默认情况下 BroadcastServicerProvider
被禁用,可能是因为它很少使用。
所有这些服务提供者都是从上到下执行的,两次迭代该列表。
第一次迭代是查找一个可选的 register()
方法,该方法可能用于在 boot()
方法之前启动某些东西。在我以往的经验中,我从未使用过它。
然后,第二次迭代执行所有提供者的 boot()
方法。再次,从 'providers'
数组的顶部到底部,一个接一个地执行。
然后,在所有服务提供者都被处理之后,Laravel 开始解析路由,执行控制器,使用模型等等。
创建您自己的自定义服务提供者
除了现有的默认文件之外,您还可以轻松创建自己的服务提供者,与 auth/event/routes 等默认主题相关的其他主题。
一个非常典型的例子是与 Blade 视图相关的配置。如果要创建 Blade 指令,您可以将该代码添加到任何服务提供者的 boot()
方法中,包括默认的 AppServiceProvider
,但开发人员通常会创建一个单独的 ViewServiceProvider。
您可以使用以下命令生成它
php artisan make:provider ViewServiceProvider
它将生成默认模板
namespace App\Providers; use Illuminate\Support\ServiceProvider; class ViewServiceProvider extends ServiceProvider{ /** * Register services. * * @return void */ public function register() { // } /** * Bootstrap services. * * @return void */ public function boot() { // }}
您可以删除 register()
方法,并在 boot()
中添加 Blade 指令代码
use Illuminate\Support\Facades\Blade; public function boot(){ Blade::directive('datetime', function ($expression) { return "<?php echo ($expression)->format('m/d/Y H:i'); ?>"; });}
ViewServiceProvider 的另一个例子是关于视图合成器,这是 来自 Laravel 官方文档的代码片段
use App\View\Composers\ProfileComposer;use Illuminate\Support\Facades\View;use Illuminate\Support\ServiceProvider; class ViewServiceProvider extends ServiceProvider{ public function boot() { // Using class based composers... View::composer('profile', ProfileComposer::class); // Using closure based composers... View::composer('dashboard', function ($view) { // }); }}
要执行,此新提供者应添加到 config/app.php
中的提供者数组中,如上所述
return [ // ... other configuration values 'providers' => [ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, // Add your provider here App\Providers\ViewServiceProvider::class, ],];
来自开源项目的示例
最后,我想提几个来自免费提供的 Laravel 项目的例子。
1. spatie/freek.dev: BladeComponentServiceProvider
一家知名公司 Spatie 发布了 Freek Van der Herten 个人博客的源代码,其中包含此文件。
app/Providers/BladeComponentServiceProvider.php:
namespace App\Providers; use App\Http\Components\AdComponent;use Illuminate\Support\Facades\Blade;use Illuminate\Support\ServiceProvider; class BladeComponentServiceProvider extends ServiceProvider{ public function boot() { Blade::component('ad', AdComponent::class); Blade::component('front.components.inputField', 'input-field'); Blade::component('front.components.submitButton', 'submit-button'); Blade::component('front.components.textarea', 'textarea'); Blade::component('front.components.textarea', 'textarea'); Blade::component('front.components.shareButton', 'share-button'); Blade::component('front.components.lazy', 'lazy'); Blade::component('front.components.postHeader', 'post-header'); Blade::component('front.layouts.app', 'app-layout'); }}
2. monicahq/monica: MacroServiceProvider
最受欢迎的 Laravel 开源项目之一有一个单独的文件来注册 Collection 宏
app/Providers/MacroServiceProvider.php:
namespace App\Providers; use App\Helpers\CollectionHelper;use Illuminate\Support\Collection;use Illuminate\Support\ServiceProvider; class MacroServiceProvider extends ServiceProvider{ /** * Bootstrap any application services. * * @return void */ public function boot() { if (! Collection::hasMacro('sortByCollator')) { Collection::macro('sortByCollator', function ($callback, $options = \Collator::SORT_STRING, $descending = false) { /** @var Collection */ $collect = $this; return CollectionHelper::sortByCollator($collect, $callback, $options, $descending); }); } if (! Collection::hasMacro('groupByItemsProperty')) { Collection::macro('groupByItemsProperty', function ($property) { /** @var Collection */ $collect = $this; return CollectionHelper::groupByItemsProperty($collect, $property); }); } if (! Collection::hasMacro('mapUuid')) { Collection::macro('mapUuid', function () { /** @var Collection */ $collect = $this; return $collect->map(function ($item) { return $item->uuid; })->toArray(); }); } }}
3. phpreel/phpreelcms: DashboardComponentsServiceProvider
名为 phpReel 的 Laravel CMS 还有一个用于 Blade 组件的服务提供者,名称更长。
app/Providers/DashboardComponentsServiceProvider.php:
namespace App\Providers; use Illuminate\Support\ServiceProvider;use Illuminate\Support\Facades\Blade;use App\Helpers\FileUpload\UploadComponents; class DashboardComponentsServiceProvider extends ServiceProvider{ /** * Register services. * * @return void */ public function register() { // } /** * Bootstrap services. * * @return void */ public function boot() { Blade::directive('uploadForm', function () { $component = UploadComponents::getUploadForm(); $html = '<?php echo \'' . $component . '\'; ?>'; return ('<?php echo "' . $component . '"; ?>'); }); }}
您还可以在我的 LaravelExamples.com 网站 上找到更多服务提供者的示例。