Dependency Injection
Symfony resolves and injects services into your code via the container, instead of you newing things up.
- A "service" is just a class managed by the container — typically with logic you want to share.
- Constructor injection is the default. Type-hint a service in your constructor and Symfony provides it.
- Autowiring uses the type-hint to figure out which concrete class to inject, no config required.
- Autoconfiguration applies tags automatically based on interfaces (e.g. EventSubscriberInterface).
- When more than one class implements an interface, you must alias or bind the right one explicitly.
- Services are singletons by default — one instance per request. Mark them shared: false to change that.
// src/Service/Mailer.php
class Mailer
{
public function __construct(private LoggerInterface $logger) {}
}
// Anywhere else
class NotifyController
{
public function __construct(private Mailer $mailer) {}
}
Common gotchas
- Don't confuse autowiring (resolving constructor args by type) with autoconfiguration (applying tags by interface). They run together but do different things.
- Public vs private services: in Symfony 4+ services are private by default. You inject them — you do not pull them from `\$container->get()`.
- Circular dependencies fail at compile time, not runtime. Read the error — it usually points at the cycle.