PHP cookbook · Intermediate
Wire a PHP app with a DI container
Stop creating dependencies with `new` all over the code and make classes testable.
Approach
Use constructor injection everywhere and let a PSR-11 container (PHP-DI, Symfony DependencyInjection) build objects through autowiring. Bind interfaces to implementations in one place (the composition root) and keep $container->get() out of business code.
Solution
<?php
declare(strict_types=1);
use DI\ContainerBuilder;
use function DI\autowire;
use function DI\factory;
$builder = new ContainerBuilder();
$builder->enableCompilation(__DIR__ . '/var/cache'); // fast in production
$builder->addDefinitions([
PDO::class => factory(fn () => createPdo()),
OrderRepository::class => autowire(PdoOrderRepository::class),
PaymentGateway::class => autowire(StripeGateway::class)->constructorParameter('apiKey', getenv('STRIPE_KEY')),
Psr\Log\LoggerInterface::class => factory(fn () => createLogger()),
]);
$container = $builder->build();
// Composition root (front controller / router) only:
$controller = $container->get(CheckoutController::class);
$response = $controller->handle($request);
// In tests, no container needed:
$service = new CheckoutService(new InMemoryOrderRepository(), new FakePaymentGateway());
Pitfalls
- Injecting the container into services (service locator).
- Global singletons via static methods instead of container-managed shared instances.
- Runtime reflection autowiring without compilation in production.
Variations
- Symfony: autowiring and autoconfiguration in
services.yaml. - Laravel: service providers and contextual binding.
Further reading: PHP-DI: Getting started
Reference: https://php-di.org/doc/getting-started.html
More PHP recipes
- Add CSRF protection to PHP forms
- Add health check endpoints to a PHP app
- Add structured logging with request IDs in PHP
- Build a secure password reset flow in PHP
- Cache expensive queries with Redis in PHP
- Call external APIs with timeouts and retries in PHP
- Handle file uploads securely in PHP
- Implement rate limiting in a PHP API