Symfony 6 Dependency Injection: A Simple Guide with Examples

Symfony, a popular PHP framework, is well-known for its robustness and developer-friendly tools.
One of its most powerful features is Dependency Injection (DI), which promotes cleaner, more testable, and more maintainable code.
This blog delves into the concept of Dependency Injection in Symfony 6, providing examples and explanations to get you started.
🪄Not a member? Click HERE
What is Dependency Injection?
Dependency Injection is a design pattern where an object receives its dependencies from an external source rather than creating them itself.
This allows for greater flexibility and modularity, making your code easier to maintain and test.
In Symfony, the Service Container is at the heart of DI. It holds and manages the lifecycle of all your services (classes designed to perform specific tasks).
🧿Why Use Dependency Injection?

- Separation of Concerns: Classes focus on their logic rather than managing dependencies.
- Improved Testability: Dependencies can be mocked or replaced for unit testing.
- Reusability: Services can be reused across your application.
- Flexibility: Configurations can be changed without modifying the core logic.
🔮 Configuring Services in Symfony 6
Symfony automatically registers services in the src/
directory when following its conventions.
Let’s walk through an example.
📫 Example: Creating and Injecting a Service
Step 1: Define a Service Class
Create a class in the src/Service
directory:
// src/Service/GreetingService.php
namespace App\Service;
class GreetingService
{
public function getGreeting(string $name): string
{
return "Hello, $name!";
}
}
Step 2: Inject the Service into a Controller
Symfony automatically registers your service in the container if it’s under the src/
directory and follows PSR-4 autoloading.
Use it in a controller:
// src/Controller/GreetingController.php
namespace App\Controller;
use App\Service\GreetingService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class GreetingController extends AbstractController
{
private GreetingService $greetingService;
public function __construct(GreetingService $greetingService)
{
$this->greetingService = $greetingService;
}
#[Route('/greet/{name}', name: 'greet')]
public function greet(string $name): Response
{
$message = $this->greetingService->getGreeting($name);
return new Response($message);
}
}
How It Works:
- Symfony’s service container automatically injects the
GreetingService
instance into the controller’s constructor. - The
greet
route uses this service to generate a greeting message.
⚙️ Customizing Service Configuration
Sometimes, you need to configure services explicitly in config/services.yaml
:
services:
App\Service\GreetingService:
arguments:
$prefix: 'Welcome'
Modify the service to accept a prefix argument:
// src/Service/GreetingService.php
namespace App\Service;
class GreetingService
{
private string $prefix;
public function __construct(string $prefix = 'Hello')
{
$this->prefix = $prefix;
}
public function getGreeting(string $name): string
{
return "{$this->prefix}, $name!";
}
}
This approach provides flexibility to tweak service behavior without changing the code.
🧯 Other Dependency Injection Techniques
1. Setter Injection
Instead of injecting services via the constructor, you can inject them using setters.
// src/Service/GreetingService.php
class GreetingService
{
private LoggerInterface $logger;
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
}
Configure in services.yaml
:
services:
App\Service\GreetingService:
calls:
- method: 'setLogger'
arguments:
- '@logger'
2. Autowiring
Symfony uses autowiring by default, allowing you to omit explicit service definitions.
It resolves dependencies based on type hints in constructors or setters.
For example, injecting LoggerInterface
:
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
No configuration is needed as Symfony knows how to provide a logger service.
⏰ Testing with Dependency Injection
Dependency Injection facilitates unit testing by allowing mock services.
For instance, testing the GreetingController
:
use PHPUnit\Framework\TestCase;
use App\Service\GreetingService;
use App\Controller\GreetingController;
class GreetingControllerTest extends TestCase
{
public function testGreet(): void
{
$mockService = $this->createMock(GreetingService::class);
$mockService->method('getGreeting')->willReturn('Hello, Mock!');
$controller = new GreetingController($mockService);
$response = $controller->greet('John');
$this->assertSame('Hello, Mock!', $response->getContent());
}
}
📍Conclusion
Symfony 6’s Dependency Injection system is a cornerstone of its flexibility and power.
By leveraging the service container and autowiring, developers can build scalable and maintainable applications.
Whether you’re injecting services into controllers or customizing service definitions, Symfony’s DI system simplifies application development.
Dependency Injection is a vast topic, and this guide scratches the surface. Explore further to master its nuances, and you’ll unlock the full potential of Symfony 6 in your projects.
🎉 Symfony Topics



Thank you for reading. Before you go 🙋♂️:
Please clap for the writer ️👏️️
🔔 Follow me: https://medium.com/@mayurkoshti12