Controller Injection

Dependency Injection in Controllers

The service container (The Service Container) builds every controller, so constructor and action parameters are resolved by type: Request, bound models, services. Concrete classes need no registration, and contextual attributes such as #[Config] inject configuration values.

A service injected into ProductController's constructorPHP
public function __construct(                     // app/Services/Currency.php
    #[Config('app.currency', 'USD')] private string $code,
    #[Config('app.locale')] string $locale,
) { /* builds a NumberFormatter: format(34.5) returns "$34.50" */ }
public function __construct(private Currency $currency) {}      // ProductController

An interface needs a binding. The invokable CheckoutController asks for PaymentGateway:

Output of 46
$ curl -s -X POST -H 'Accept: application/json' -d card=4242424242424242 $B/api/checkout/1 \
    | jq -r .message | fold -w 90
Target [App\Contracts\PaymentGateway] is not instantiable while building [App\Http\Control
lers\CheckoutController].
$ curl -s -X POST -H 'Accept: application/json' -d card=4242424242424242 $B/api/checkout/1
{"charged":39.99,"card":"**** 4242","ok":true}

The second call followed #[Bind(FakeGateway::class)] on the interface (or $this->app->bind(), Binding Interfaces). Inject dependencies rather than calling app() inside actions, so tests can swap them.