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

Di Container Laravel Package

sanmai/di-container

Lightweight PSR-11 compatible dependency injection container for PHP. Supports autowiring via reflection, bindings and shared services, simple configuration, and fast resolution with minimal boilerplate—suitable for small apps and libraries needing a straightforward DI container.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by installing the package via Composer:

composer require sanmai/di-container

The core class is Sanmai\DI\Container. Instantiate it, register services via closures (factories), then resolve them:

use Sanmai\DI\Container;

$container = new Container();

// Register a singleton
$container->register(PDO::class, fn () => new PDO('sqlite::memory:'));
// Register a non-shared (transient) service with optional dependencies
$container->register(LoggerInterface::class, fn ($c) => new StdOutLogger($c->get(OptionalDependency::class)));

// Resolve a dependency (dependencies are auto-injected if type-hinted)
$logger = $container->resolve(LoggerInterface::class);

First use case: Bootstrapping a simple application where services are defined in one place (e.g., bootstrap/app.php), then resolved on demand in controllers, commands, or services. The new release improves handling of optional dependencies, allowing graceful resolution even if a type is missing.


Implementation Patterns

  • Configuration-driven registration: Group related services into service providers or static methods:

    class DatabaseServiceProviders {
      public static function register(Container $container): void {
        $container->register(PDO::class, fn () => new PDO($_ENV['DB_DSN']));
        $container->register(EntityManager::class, fn ($c) => new EntityManager($c->get(PDO::class)));
      }
    }
    DatabaseServiceProviders::register($container);
    
  • Handling optional dependencies: Use type-hinted parameters in factories for optional services. If the dependency is missing, the closure will still execute (no exception thrown):

    $container->register(
      CacheService::class,
      fn ($c) => new CacheService($c->get(OptionalRedisClient::class)) // Gracefully handles missing Redis
    );
    
  • Lazy-loading expensive services: Wrap factories in lazy() to defer instantiation:

    $container->register('db.connection', fn () => lazy(fn () => new PDO(...)));
    // Only instantiated on first access
    
  • Interface-based wiring: Prefer registering services as interfaces (e.g., CacheInterface) and resolving concrete implementations — great for swapping implementations (e.g., Redis vs. array cache) or testing.

  • Integration with PSR-11: Container implements Psr\Container\ContainerInterface, enabling compatibility with PSR-11-consuming libraries (e.g., nyholm/psr7, symfony/http-kernel adapters).

  • Nested containers: For modular apps or test fixtures, compose containers:

    $base = new Container();
    $base->register(...);
    $testContainer = new Container($base);
    $testContainer->override(SessionInterface::class, MockSession::class);
    

Gotchas and Tips

  • Circular dependencies cause recursion: If A depends on B and B depends on A, resolution will blow the stack. Diagnose via stack traces; refactor to constructor injection with deferred dependencies (e.g., callable or factory arguments).

  • get() vs resolve(): Both resolve services, but resolve() supports type-hinted autowiring for closure arguments (e.g., fn (PDO $pdo) => new Repository($pdo)), while get() requires explicit class names or IDs.

  • Shared services must be explicitly declared: By default, services are transient. Use share() to make them singletons:

    $container->share(PDO::class, fn () => new PDO('...'));
    
  • Overriding registrations: Use override() (non-reentrant) or replace() for test doubles (e.g., mocking services):

    $container->replace(PDO::class, fn () => new MockPDO());
    
  • Optional dependencies are now skipped gracefully: If a type-hinted dependency in a factory closure is not registered, the closure will execute without throwing an exception (new in 0.1.16). Example:

    $container->register(
      UserRepository::class,
      fn ($c) => new UserRepository($c->get(OptionalAnalyticsService::class)) // No error if missing
    );
    
  • IDE autocompletion: For better UX, cast container type hints in your codebase or use Container::with() to build typed sub-containers.

  • No built-in config layer: You must inject config arrays yourself — e.g., fn () => new Service(config('my.service')). This keeps it minimal but requires you to define a config loader separately (e.g., using symfony/dependency-injection’s config parser or custom loader).

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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle