php 45 lines · 7 steps

Binding a payment gateway in Laravel

A deferred service provider wires an interface to the right implementation based on environment and config.

Explained by highlit
1<?php
2 
3namespace App\Providers;
4 
5use App\Contracts\PaymentGateway;
6use App\Services\Payments\FakePaymentGateway;
7use App\Services\Payments\StripePaymentGateway;
8use Illuminate\Contracts\Support\DeferrableProvider;
9use Illuminate\Support\ServiceProvider;
10use Stripe\StripeClient;
11 
12class PaymentServiceProvider extends ServiceProvider implements DeferrableProvider
13{
14 public function register(): void
15 {
16 $this->app->bind(PaymentGateway::class, function ($app) {
17 $config = $app['config']['services.stripe'];
18 
19 if ($app->environment('testing') || empty($config['secret'])) {
20 return new FakePaymentGateway();
21 }
22 
23 return new StripePaymentGateway(
24 new StripeClient($config['secret']),
25 $config['webhook_secret'] ?? null,
26 );
27 });
28 
29 $this->app->singleton(StripeClient::class, function ($app) {
30 return new StripeClient($app['config']['services.stripe.secret']);
31 });
32 
33 $this->app->when(StripePaymentGateway::class)
34 ->needs('$currency')
35 ->giveConfig('services.stripe.currency', 'usd');
36 }
37 
38 public function provides(): array
39 {
40 return [
41 PaymentGateway::class,
42 StripeClient::class,
43 ];
44 }
45}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Binding to an interface lets you swap implementations without touching the code that depends on it.
  2. 2Resolving the implementation inside a closure defers the decision until the service is actually needed.
  3. 3Deferred providers list what they provide so Laravel can skip booting them until something asks.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Binding a payment gateway in Laravel — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code