What I prefer about Laravel Dependency Injection over Symfony

Regarding Laravel, one of the biggest "no"s in 2022 was how it handles passing services around the project. I'm not talking about the facades or active records but the static reflection container.

At first, it raised my blood pressure - we have a dependency injection, and everything must be passed via the constructor, right?

Then I remembered a wise saying: "There are no best solutions, only trade-offs."

Disclaimer: I'll write more about Laravel DI features and how I approach it, but there is single one that stands out for me and I wanted to share it with you.


Let's start with what most of my readers and I know well - Symfony.


How do we work with services in Symfony?

To get a service in a Symfony project, we have to:

  1. register it explicitly or via PSR-4 autodiscovery
return function (ContainerConfigurator $containerConfigurator): void {
    $services = $containerConfigurator->services();

    $services->defaults()->autowire();

    $services->load('App\\', __DIR__ . '/../src/App');
}
  1. then require it in a constructor
final class SomeClass
{
    public function __construct(
        private readonly ProductRepository $productRepository
    ) {
    }
}

Opt-Out

From over 50+ Symfony project upgrades, what is the most costly and repeated step?

The configs:

I call this approach an opt-out:

This memory-lock forces us to think about another more place when we want to use the service. This lead to distraction and unfocused programming.

How do we get service in Laravel?

Laravel is one less step easier. Do you need a service? Ask for it:

final class SomeClass
{
    public function __construct(
        private readonly ProductRepository $productRepository
    ) {
    }
}

Opt-in

With this approach, it seems we have 50 % less work. It's much more, as we only focus on one point at a time and are more with deep work.

I have very limited Laravel DI knowledge, so bear with me: when we ask for a service, and it's not created yet, the container will create one, inject the dependencies and provide it. I thought, "This uses reflection, and reflection is bad". But that's as dogmatic as "all drugs are bad, and you should never visit a professional psychiatrist".

Simplicity teaches best practices

We only modify the config file (service provider) when we need to do something extra, unique, or weird. I've noticed this motivates me to use as many clean services as possible, without any scalar parameters, magic injections, or multiple instances of one type.

This naturally leads to cleaner architecture, simpler code, and a smaller set of coding patterns. This leads to code that another developer finds easier to read and understand and requires less cognitive load to work with effectively.


I'm delighted this is a positive externality that works on a subconscious level and makes my code cleaner.

What is your experience with Laravel or Symfony dependency injection?


Happy coding!




Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors. I'd really appreciate it!