Laravel 13 服务提供者完全指南

服务提供者是 Laravel 应用的核心引导机制,负责注册服务容器绑定和配置应用的各种服务。本文将深入探讨 Laravel 13 中服务提供者的最佳实践和高级用法。

服务提供者基础

创建服务提供者

1
php artisan make:provider PaymentServiceProvider

生成的服务提供者结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class PaymentServiceProvider extends ServiceProvider
{
public function register(): void
{
// 注册服务绑定
}

public function boot(): void
{
// 引导服务
}
}

注册与引导的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class PaymentServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(PaymentGatewayInterface::class, function ($app) {
return new StripeGateway(
config('services.stripe.secret')
);
});

$this->app->bind(PaymentCalculator::class, function ($app) {
return new PaymentCalculator(
$app->make(TaxService::class)
);
});
}

public function boot(): void
{
View::composer('payment.*', PaymentViewComposer::class);

Gate::policy(Order::class, OrderPolicy::class);

Route::model('order', Order::class);
}
}

注册服务绑定

单例绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
public function register(): void
{
$this->app->singleton(LoggerService::class, function ($app) {
return new LoggerService(
$app->make('log'),
config('logging.channels.custom')
);
});

$this->app->singleton('payment', function ($app) {
return new PaymentManager($app);
});
}

绑定接口到实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function register(): void
{
$this->app->bind(
RepositoryInterface::class,
EloquentRepository::class
);

$this->app->bind(
CacheInterface::class,
RedisCache::class
);

$this->app->bind(
QueueInterface::class,
RedisQueue::class
);
}

上下文绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use App\Contracts\LoggerInterface;
use App\Services\DatabaseLogger;
use App\Services\FileLogger;

public function register(): void
{
$this->app->when(OrderController::class)
->needs(LoggerInterface::class)
->give(DatabaseLogger::class);

$this->app->when(PaymentController::class)
->needs(LoggerInterface::class)
->give(FileLogger::class);

$this->app->when(ReportService::class)
->needs('$reportType')
->give(config('reports.default_type'));
}

标记服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public function register(): void
{
$this->app->singleton(EmailHandler::class);
$this->app->singleton(SmsHandler::class);
$this->app->singleton(PushHandler::class);

$this->app->tag([
EmailHandler::class,
SmsHandler::class,
PushHandler::class,
], 'notification.handlers');
}

public function boot(): void
{
$handlers = $this->app->tagged('notification.handlers');

foreach ($handlers as $handler) {
$this->notificationManager->register($handler);
}
}

延迟加载提供者

创建延迟提供者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\HeavyService;

class HeavyServiceProvider extends ServiceProvider
{
protected bool $defer = true;

public function register(): void
{
$this->app->singleton(HeavyService::class, function ($app) {
return new HeavyService();
});
}

public function provides(): array
{
return [HeavyService::class];
}
}

条件加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class OptionalServiceProvider extends ServiceProvider
{
protected bool $defer = true;

public function register(): void
{
if (class_exists('SomePackage\Service')) {
$this->app->singleton('some.service', function ($app) {
return new \SomePackage\Service();
});
}
}

public function provides(): array
{
return ['some.service'];
}
}

配置发布

发布配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function boot(): void
{
$this->publishes([
__DIR__ . '/../../config/payment.php' => config_path('payment.php'),
], 'config');

$this->publishes([
__DIR__ . '/../../database/migrations/' => database_path('migrations'),
], 'migrations');

$this->publishes([
__DIR__ . '/../../resources/views/' => resource_path('views/vendor/payment'),
], 'views');
}

合并配置

1
2
3
4
5
6
7
public function register(): void
{
$this->mergeConfigFrom(
__DIR__ . '/../../config/payment.php',
'payment'
);
}

发布组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function boot(): void
{
$this->publishes([
__DIR__ . '/../../config/payment.php' => config_path('payment.php'),
], 'payment-config');

$this->publishes([
__DIR__ . '/../../resources/views/' => resource_path('views/vendor/payment'),
], 'payment-views');

$this->publishes([
__DIR__ . '/../../public/' => public_path('vendor/payment'),
], 'payment-assets');
}

命令注册

注册 Artisan 命令

1
2
3
4
5
6
7
8
9
10
public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->commands([
ProcessPaymentCommand::class,
GenerateReportCommand::class,
CleanupExpiredTokensCommand::class,
]);
}
}

计划任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Illuminate\Support\Facades\Schedule;

public function boot(): void
{
Schedule::command('payments:process')
->everyMinute()
->withoutOverlapping();

Schedule::command('reports:generate --daily')
->dailyAt('02:00')
->onOneServer();

Schedule::job(new CleanupJob())
->hourly()
->graceTime(5);
}

视图与路由注册

加载视图

1
2
3
4
5
6
7
8
9
10
11
12
public function boot(): void
{
$this->loadViewsFrom(
__DIR__ . '/../../resources/views',
'payment'
);

$this->loadViewComponentsAs('payment', [
'card' => PaymentCardComponent::class,
'form' => PaymentFormComponent::class,
]);
}

加载路由

1
2
3
4
5
public function boot(): void
{
$this->loadRoutesFrom(__DIR__ . '/../../routes/web.php');
$this->loadRoutesFrom(__DIR__ . '/../../routes/api.php');
}

加载迁移

1
2
3
4
public function boot(): void
{
$this->loadMigrationsFrom(__DIR__ . '/../../database/migrations');
}

加载翻译

1
2
3
4
5
6
7
public function boot(): void
{
$this->loadTranslationsFrom(
__DIR__ . '/../../resources/lang',
'payment'
);
}

高级用法

工厂模式绑定

1
2
3
4
5
6
7
8
9
10
public function register(): void
{
$this->app->singleton(PaymentFactory::class, function ($app) {
return new PaymentFactory([
'stripe' => fn() => $app->make(StripeGateway::class),
'paypal' => fn() => $app->make(PayPalGateway::class),
'alipay' => fn() => $app->make(AlipayGateway::class),
]);
});
}

装饰器模式

1
2
3
4
5
6
public function register(): void
{
$this->app->extend(RepositoryInterface::class, function ($repository, $app) {
return new CachedRepository($repository, $app->make(Cache::class));
});
}

解析回调

1
2
3
4
5
6
7
8
9
10
11
12
public function register(): void
{
$this->app->resolving(RepositoryInterface::class, function ($repo, $app) {
$repo->setLogger($app->make('log'));
});

$this->app->resolving(function ($object, $app) {
if (method_exists($object, 'setContainer')) {
$object->setContainer($app);
}
});
}

服务提供者最佳实践

单一职责

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class PaymentServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->registerGateways();
$this->registerCalculator();
$this->registerValidator();
}

protected function registerGateways(): void
{
$this->app->singleton(StripeGateway::class, function ($app) {
return new StripeGateway(config('services.stripe'));
});
}

protected function registerCalculator(): void
{
$this->app->singleton(PaymentCalculator::class);
}

protected function registerValidator(): void
{
$this->app->singleton(PaymentValidator::class);
}
}

配置验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function boot(): void
{
if (config('payment.enabled')) {
$this->validateConfiguration();
}
}

protected function validateConfiguration(): void
{
$required = ['payment.gateway', 'payment.currency'];

foreach ($required as $key) {
if (empty(config($key))) {
throw new \RuntimeException("Missing required config: {$key}");
}
}
}

条件注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public function register(): void
{
if (!$this->app->configurationIsCached()) {
$this->mergeConfigFrom(
__DIR__ . '/../../config/payment.php',
'payment'
);
}
}

public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->commands([PaymentCommand::class]);
}

if (!$this->app->routesAreCached()) {
$this->loadRoutesFrom(__DIR__ . '/../../routes/api.php');
}
}

测试服务提供者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

namespace Tests\Unit\Providers;

use Tests\TestCase;
use App\Providers\PaymentServiceProvider;
use App\Contracts\PaymentGatewayInterface;
use App\Services\StripeGateway;

class PaymentServiceProviderTest extends TestCase
{
protected function getPackageProviders($app): array
{
return [PaymentServiceProvider::class];
}

public function test_it_binds_payment_gateway(): void
{
$gateway = $this->app->make(PaymentGatewayInterface::class);

$this->assertInstanceOf(StripeGateway::class, $gateway);
}

public function test_it_registers_singleton(): void
{
$gateway1 = $this->app->make(PaymentGatewayInterface::class);
$gateway2 = $this->app->make(PaymentGatewayInterface::class);

$this->assertSame($gateway1, $gateway2);
}
}

总结

Laravel 13 的服务提供者提供了强大的服务注册和引导机制。通过合理使用服务提供者,可以实现:

  • 清晰的服务绑定和依赖注入
  • 模块化的应用架构
  • 延迟加载提升性能
  • 可测试的代码结构
  • 可复用的功能包

掌握服务提供者的使用是成为 Laravel 高级开发者的必经之路。