Good Code
The good version declares the concrete payment gateway at a provider boundary. Services can request the contract without knowing which SDK or credential setup is used.
Lesson 04
Use Laravel's service container to declare infrastructure choices once and inject contracts into application services.
<?php
namespace App\Providers;
use App\Billing\PaymentGateway;
use App\Billing\StripePaymentGateway;
use Illuminate\Support\ServiceProvider;
final class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
// The container owns the infrastructure choice for the payment contract.
$this->app->bind(PaymentGateway::class, StripePaymentGateway::class);
}
}<?php
final class CheckoutService
{
public function charge(Order $order): Receipt
{
// Creating infrastructure here couples the use case to env and SDK setup.
$client = new Stripe\StripeClient(config('services.stripe.secret'));
return $client->charges->create([
'amount' => $order->total_cents,
'currency' => 'usd',
]);
}
}The good version declares the concrete payment gateway at a provider boundary. Services can request the contract without knowing which SDK or credential setup is used.
The bad version creates the SDK client inside the use case. That makes tests depend on configuration and pushes infrastructure choices into business code.