Constructor Injection Over Property Setting in Laravel Service Providers

πŸ“– 2 minutes read

I was reviewing a service provider that registered a class by newing it up and then setting properties on it with extend(). It worked, but it was fragile β€” properties could be overwritten later, and you couldn’t make them readonly.

The Before

// AppServiceProvider.php
$this->app->bind(NotificationPlugin::class, function ($app) {
    $plugin = new NotificationPlugin();
    $plugin->apiKey = config('services.notify.key');
    $plugin->endpoint = config('services.notify.url');
    $plugin->timeout = 30;
    return $plugin;
});

This pattern has a few problems:

  • Properties are mutable β€” anything can overwrite $plugin->apiKey later
  • No way to use PHP 8.1’s readonly keyword
  • If you forget to set a property, you get a runtime error instead of a constructor error
  • Hard to test β€” you need to set up each property individually in tests

The After

class NotificationPlugin
{
    public function __construct(
        public readonly string $apiKey,
        public readonly string $endpoint,
        public readonly int $timeout = 30,
    ) {}
}

// AppServiceProvider.php
$this->app->bind(NotificationPlugin::class, function ($app) {
    return new NotificationPlugin(
        apiKey: config('services.notify.key'),
        endpoint: config('services.notify.url'),
        timeout: 30,
    );
});

What You Get

Immutability. Once constructed, the object can’t be modified. readonly enforces this at the language level.

Fail fast. If you forget a required parameter, PHP throws a TypeError at construction time β€” not some random null error 200 lines later.

Easy testing. Just new NotificationPlugin('test-key', 'http://localhost', 5). No setup ceremony.

Named arguments make it readable. PHP 8’s named parameters mean the service provider binding reads like a config file.

The Rule

If you’re setting properties on an object after construction in a service provider, refactor to constructor injection. It’s more explicit, more testable, and lets you use readonly. Your future self will thank you when debugging a “how did this property change?” mystery.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *