symfony/dependency-injection
Symfony DependencyInjection component standardizes and centralizes object construction via a service container. Define services, parameters, and wiring, support autowiring and compilation, and manage dependencies consistently across applications and libraries.
To leverage symfony/dependency-injection in Laravel, start by installing the package via Composer:
composer require symfony/dependency-injection
Initialize a container in a Laravel service provider (e.g., AppServiceProvider):
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
public function register()
{
$container = new ContainerBuilder();
// Register a service
$container->register('app.greeting', GreetingService::class)
->setArguments([new Reference('app.logger')]);
// Register a logger (simplified example)
$container->register('app.logger', Logger::class);
// Compile and bind to Laravel's container
$this->app->singleton('greeting', function ($app) use ($container) {
return $container->get('app.greeting');
});
}
ContainerBuilder: Core class for defining and managing services.Definition: Represents a service definition (class, arguments, tags, etc.).Reference: Resolves dependencies between services.CompilerPass: Customize container behavior during compilation.Use Symfony’s attribute-based autowiring:
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class GreetingService
{
public function __construct(
#[Autowire(service: 'app.logger')]
private Logger $logger
) {}
}
$container->register('app.service', ServiceClass::class)
->setArguments([new Reference('app.dependency')])
->setPublic(true); // Expose in container
$container->register('app.listener', EventListener::class)
->addTag('kernel.event_listener', ['event' => 'app.event', 'method' => 'handle']);
$container->register('app.lazy_service', LazyService::class)
->setLazy(true); // Creates a proxy
$container->setParameter('app.api_key', 'your_api_key_here');
$container->setParameter('app.config', [
'timeout' => 30,
'retries' => 3,
]);
$container->setParameter('app.db_host', '%env(DB_HOST)%');
Extend CompilerPassInterface to modify the container during compilation:
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class CustomCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('app.service')) {
return;
}
$definition = $container->getDefinition('app.service');
$definition->addMethodCall('configure', [['key' => 'value']]);
}
}
Register the pass in a service provider:
$container->addCompilerPass(new CustomCompilerPass());
Leverage Laravel’s service container to bridge Symfony’s DI:
// In a service provider
$this->app->singleton('app.symfony_service', function ($app) {
$container = new ContainerBuilder();
$container->register('app.symfony_service', SymfonyService::class);
return $container->get('app.symfony_service');
});
Use Symfony’s attributes for type-hinted dependencies:
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
class EventDispatcher
{
public function __construct(
#[TaggedIterator('kernel.event_listener')]
private iterable $listeners
) {}
}
Create a custom extension to encapsulate configuration:
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
class AppExtension implements ExtensionInterface
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resources/config')
);
$loader->load('services.yaml');
}
}
Load it in a service provider:
$container->registerExtension(new AppExtension());
Circular Dependencies
CircularReferenceException if services depend on each other in a loop.Service Not Found
public.Lazy Services and Proxies
@serializable or implement __serialize()).->setLazy(false) for services that don’t benefit from lazy loading.Parameter Overrides
setParameter() override those in config files.%env() for environment-specific values to avoid hardcoding.Compiler Pass Order
->before() and ->after() to control execution order.Tagged Services and Iterators
TaggedIterator.Autowiring Conflicts
@Autowire to specify the constructor or method.Dump Container Contents
Use the PhpDumper to inspect the container:
$dumper = new \Symfony\Component\DependencyInjection\Dumper\PhpDumper($container);
file_put_contents('/tmp/container.php', $dumper->dump());
Enable Debug Mode
Set ContainerBuilder::DEBUG_MODE to true for verbose error messages:
$container = new ContainerBuilder();
$container->setDebug(true);
Check for Deprecated Services Symfony DI logs deprecations. Enable logging to catch them:
$container->setParameter('kernel.debug', true);
Validate Configurations
Use ContainerBuilder::validate() to catch misconfigurations early:
$container->validate();
Compile the Container For production, compile the container to a PHP file to avoid runtime overhead:
$dumper = new \Symfony\Component\DependencyInjection\Dumper\PhpDumper($container);
file_put_contents(
$container->getParameter('kernel.cache_dir').'/container.php',
$dumper->dump()
);
Avoid Unnecessary Lazy Services Lazy loading adds a small overhead. Use it only for expensive-to-initialize services.
Use setShared() Wisely
Shared services are singletons. Non-shared services are recreated on each request.
Custom Loaders
Extend Loader\LoaderInterface to support custom config formats (e.g., JSON, XML).
Parameter Processors
Implement ParameterBagInterface to add custom parameter types or validation.
Service Factories
Use FactoryDefinition for dynamic service creation:
$container->setDefinition('app.factory_service', new FactoryDefinition(
ServiceFactory::class,
['argument1', 'argument2']
));
Decorators and Decorated Services Decorate services without modifying their original definitions:
$container->register('app.decorated_service', DecoratedService::class)
->setDecoratedService('app.original_service')
->setArgument(0, new Reference('app.original_service'));
ContainerBuilder and Laravel’s Container are separate. Use adapters or bridges:
$this->app->instance('app.symfony_service', $container->get('
How can I help you explore Laravel packages today?