Laravel 服务提供者:它们是什么以及如何使用它们

发布于 作者:

Service Providers in Laravel: What They Are and How to Use Them image

对于那些没有积极使用 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.phproutes/api.php。注意,对于 API,还有不同的配置:所有路由的端点前缀 /api 和中间件 api

您可以根据自己的需要编辑这些服务提供者,它们不在 /vendor 文件夹中。当您有很多路由并且想要在自定义文件中分离它们时,通常会对该文件进行自定义。您创建 routes/auth.php 并将路由放在那里,然后您在 RouteServiceProviderboot() 方法中“启用”该文件,只需添加第三句话即可

`Route::middleware('web') // or maybe you want another middleware?
->group(base_path('routes/auth.php'));

其他默认服务提供者具有其他功能,您可以自己分析它们。除了 AppServiceProvider 之外,它是空的,就像一个占位符,供我们添加与某些全局应用程序设置相关的任何代码。

AppServiceProvider 中添加代码的一个流行例子是关于 在开发期间禁用 Eloquent 的延迟加载。为此,您只需要 添加两行boot() 方法中

// app/Providers/AppServiceProvider.php
use 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');
}
}

在 Github 上查看源代码

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();
});
}
}
}

在 Github 上查看源代码

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 . '"; ?>');
});
}
}

在 Github 上查看源代码

您还可以在我的 LaravelExamples.com 网站 上找到更多服务提供者的示例。

PovilasKorop photo

Laravel Daily 的课程和教程创建者,Laravel Daily

归档于
Cube

Laravel 新闻稿

加入 40,000 多名其他开发者,不要错过新的技巧、教程等。

Laravel Forge logo

Laravel Forge

轻松创建和管理您的服务器,并在几秒钟内部署您的 Laravel 应用程序。

Laravel Forge
Tinkerwell logo

Tinkerwell

Laravel 开发人员必备的代码运行器。使用 AI、自动完成和本地和生产环境的即时反馈进行调试。

Tinkerwell
No Compromises logo

无妥协

来自 No Compromises 播客的两名资深开发者 Joel 和 Aaron 现已开放接单,为您的 Laravel 项目提供服务。 ⬧ 每月固定价格 7500 美元。 ⬧ 无冗长的销售流程。 ⬧ 无需签订合同。 ⬧ 100% 退款保证。

无妥协
Kirschbaum logo

Kirschbaum

提供创新和稳定性,确保您的 Web 应用程序取得成功。

Kirschbaum
Shift logo

Shift

正在运行旧版本的 Laravel?即时、自动化的 Laravel 升级和代码现代化,让您的应用程序焕然一新。

Shift
Bacancy logo

Bacancy

只需每月 2500 美元,即可让经验丰富的 Laravel 开发人员(4-6 年经验)为您的项目增光添彩。获得 160 小时的专业知识和 15 天的无风险试用。立即安排通话!

Bacancy
Lucky Media logo

Lucky Media

立即获得 Lucky - Laravel 开发的理想选择,拥有十多年的经验!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar:Laravel 电子商务

Laravel 的电子商务。一个开源软件包,将现代无头电子商务功能的力量带到 Laravel。

Lunar:Laravel 电子商务
LaraJobs logo

LaraJobs

官方 Laravel 招聘网站

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit:Laravel SaaS 启动套件

SaaSykit 是一个 Laravel SaaS 启动套件,包含运行现代 SaaS 所需的所有功能。支付、精美结账、管理面板、用户仪表板、身份验证、现成组件、统计信息、博客、文档等。

SaaSykit:Laravel SaaS 启动套件
Rector logo

Rector

您无缝升级 Laravel 的合作伙伴,降低成本,加速创新,帮助企业取得成功。

Rector
MongoDB logo

MongoDB

通过将 MongoDB 和 Laravel 强力集成,增强您的 PHP 应用程序,使开发人员能够轻松高效地构建应用程序。支持事务性、搜索、分析和移动用例,同时使用熟悉的 Eloquent API。了解 MongoDB 灵活性、现代数据库如何改变您的 Laravel 应用程序。

MongoDB
Maska is a Simple Zero-dependency Input Mask Library image

Maska 是一个简单的零依赖输入掩码库

阅读文章
Add Swagger UI to Your Laravel Application image

将 Swagger UI 添加到您的 Laravel 应用程序

阅读文章
Assert the Exact JSON Structure of a Response in Laravel 11.19 image

在 Laravel 11.19 中断言响应的精确 JSON 结构

阅读文章
Build SSH Apps with PHP and Laravel Prompts image

使用 PHP 和 Laravel 提示构建 SSH 应用程序

阅读文章
Building fast, fuzzy site search with Laravel and Typesense image

使用 Laravel 和 Typesense 构建快速模糊站点搜索

阅读文章
Add Comments to your Laravel Application with the Commenter Package image

使用 Commenter 软件包在您的 Laravel 应用程序中添加评论

阅读文章