Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Dependency Injection Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

To leverage symfony/dependency-injection in Laravel, start by installing the package via Composer:

composer require symfony/dependency-injection

First Use Case: Basic Container Initialization

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');
    });
}

Key Entry Points

  • 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.

Quick Start with Attributes (Laravel 9+)

Use Symfony’s attribute-based autowiring:

use Symfony\Component\DependencyInjection\Attribute\Autowire;

class GreetingService
{
    public function __construct(
        #[Autowire(service: 'app.logger')]
        private Logger $logger
    ) {}
}

Implementation Patterns

1. Service Registration and Configuration

Basic Registration

$container->register('app.service', ServiceClass::class)
    ->setArguments([new Reference('app.dependency')])
    ->setPublic(true); // Expose in container

Tagging Services for Collection

$container->register('app.listener', EventListener::class)
    ->addTag('kernel.event_listener', ['event' => 'app.event', 'method' => 'handle']);

Lazy Services

$container->register('app.lazy_service', LazyService::class)
    ->setLazy(true); // Creates a proxy

2. Parameter Binding

Scalar and Complex Parameters

$container->setParameter('app.api_key', 'your_api_key_here');
$container->setParameter('app.config', [
    'timeout' => 30,
    'retries' => 3,
]);

Environment Variables

$container->setParameter('app.db_host', '%env(DB_HOST)%');

3. Compiler Passes for Custom Logic

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());

4. Integration with Laravel’s Container

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');
});

5. Attribute-Based Configuration

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
    ) {}
}

6. Extension Patterns

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());

Gotchas and Tips

Common Pitfalls

  1. Circular Dependencies

    • Symfony DI throws CircularReferenceException if services depend on each other in a loop.
    • Fix: Use setter injection or break the cycle with interfaces.
  2. Service Not Found

    • If a service is not found, check:
      • Typos in service IDs.
      • Whether the service is marked as public.
      • Compiler passes that might remove or modify definitions.
  3. Lazy Services and Proxies

    • Lazy services create proxies, which may cause issues with:
      • Serialization (use @serializable or implement __serialize()).
      • Debugging (proxies hide the actual class in stack traces).
    • Tip: Use ->setLazy(false) for services that don’t benefit from lazy loading.
  4. Parameter Overrides

    • Parameters set via setParameter() override those in config files.
    • Tip: Use %env() for environment-specific values to avoid hardcoding.
  5. Compiler Pass Order

    • Passes run in the order they’re added. Dependencies between passes must be respected.
    • Tip: Use ->before() and ->after() to control execution order.
  6. Tagged Services and Iterators

    • Tagged services must be public to be collected by TaggedIterator.
    • Gotcha: Non-public services won’t appear in tagged collections.
  7. Autowiring Conflicts

    • If a class has multiple constructors, Symfony DI may fail to autowire.
    • Fix: Use @Autowire to specify the constructor or method.

Debugging Tips

  1. 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());
    
  2. Enable Debug Mode Set ContainerBuilder::DEBUG_MODE to true for verbose error messages:

    $container = new ContainerBuilder();
    $container->setDebug(true);
    
  3. Check for Deprecated Services Symfony DI logs deprecations. Enable logging to catch them:

    $container->setParameter('kernel.debug', true);
    
  4. Validate Configurations Use ContainerBuilder::validate() to catch misconfigurations early:

    $container->validate();
    

Performance Optimizations

  1. 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()
    );
    
  2. Avoid Unnecessary Lazy Services Lazy loading adds a small overhead. Use it only for expensive-to-initialize services.

  3. Use setShared() Wisely Shared services are singletons. Non-shared services are recreated on each request.

    • Tip: Prefer shared services for stateless operations to reduce memory usage.

Extension Points

  1. Custom Loaders Extend Loader\LoaderInterface to support custom config formats (e.g., JSON, XML).

  2. Parameter Processors Implement ParameterBagInterface to add custom parameter types or validation.

  3. Service Factories Use FactoryDefinition for dynamic service creation:

    $container->setDefinition('app.factory_service', new FactoryDefinition(
        ServiceFactory::class,
        ['argument1', 'argument2']
    ));
    
  4. 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'));
    

Laravel-Specific Quirks

  1. Binding to Laravel’s Container Symfony’s ContainerBuilder and Laravel’s Container are separate. Use adapters or bridges:
    $this->app->instance('app.symfony_service', $container->get('
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport