PHPackages                             duyler/dependency-injection - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. duyler/dependency-injection

ActiveLibrary

duyler/dependency-injection
===========================

Dependency injection container

01.6kPHPCI passing

Since May 14Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/duyler/di)[ Packagist](https://packagist.org/packages/duyler/dependency-injection)[ RSS](/packages/duyler-dependency-injection/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (8)Used By (0)

[![Quality Gate Status](https://camo.githubusercontent.com/58e185d217776a95a64b83efd02358d910578b6f47cdac020a2508c3138940ec/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d6475796c65725f6469266d65747269633d616c6572745f737461747573)](https://sonarcloud.io/summary/new_code?id=duyler_di)[![Coverage](https://camo.githubusercontent.com/d98a0fc8bde43b95d4ab8eebc0b788033176fbcfe2626610755daef31671c139/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d6475796c65725f6469266d65747269633d636f766572616765)](https://sonarcloud.io/summary/new_code?id=duyler_di)[![type-coverage](https://camo.githubusercontent.com/78ab81d8c51f8354cb459f14a508b5de753fa39e386ae5e7d686dc512092db91/68747470733a2f2f73686570686572642e6465762f6769746875622f6475796c65722f64692f636f7665726167652e737667)](https://shepherd.dev/github/duyler/di)[![psalm-level](https://camo.githubusercontent.com/99ea3aecef4b2e1f87255d7e526d0c91a57802b5f8612aa1fa0ed995597b8e6d/68747470733a2f2f73686570686572642e6465762f6769746875622f6475796c65722f64692f6c6576656c2e737667)](https://shepherd.dev/github/duyler/di)

Duyler Dependency Injection Container
=====================================

[](#duyler-dependency-injection-container)

A modern, flexible, and type-safe dependency injection container for PHP applications. This container implements the PSR-11 Container Interface and provides additional features for dependency management.

Features
--------

[](#features)

- PSR-11 Container Interface implementation
- Type-safe dependency injection
- Provider-based service registration
- Support for interface bindings
- Service finalization
- Reflection caching
- Dependency tree visualization
- Strict type checking
- Scoped services (Singleton, Transient)
- Tagged services for grouping and bulk retrieval
- Binding validation
- Callback factories
- Compile-time dependency validation
- Enhanced error messages with suggestions and context
- Debug mode with profiling and statistics
- Attribute-based configuration (PHP 8+ attributes)
- Auto-tagging by interface
- Event system with lifecycle hooks
- Service decorators for aspect-oriented programming

Installation
------------

[](#installation)

```
composer require duyler/dependency-injection
```

Basic Usage
-----------

[](#basic-usage)

### Simple Container Usage

[](#simple-container-usage)

```
use Duyler\DI\Container;

$container = new Container();

// Register a service
$container->set(new MyService());

// Get a service
$service = $container->get(MyService::class);
```

### Using Container Configuration

[](#using-container-configuration)

```
use Duyler\DI\Container;
use Duyler\DI\ContainerConfig;

$config = new ContainerConfig();
$config
    ->withBind([
        MyInterface::class => MyImplementation::class,
    ])
    ->withProvider([
        AnotherInterface::class => MyProvider::class,
    ]);

$container = new Container($config);
```

### Creating a Service Provider

[](#creating-a-service-provider)

```
use Duyler\DI\Provider\ProviderInterface;
use Duyler\DI\ContainerService;

class MyServiceProvider implements ProviderInterface
{
    public function getArguments(ContainerService $containerService): array
    {
        return [
            'dependency' => $containerService->getInstance(Dependency::class),
        ];
    }

    public function bind(): array
    {
        return [
            MyInterface::class => MyImplementation::class,
        ];
    }

    public function accept(object $definition): void
    {
        // Handle definition if needed
    }

    public function finalizer(): ?callable
    {
        return function (MyImplementation $service) {
            // Perform finalization
            $service->finalize();
        };
    }

    public function factory(ContainerService $containerService): ?object
    {
        return new MyImplementation(
            $containerService->getInstance(Dependency::class)
        );
    }
}
```

### Using Service Definitions

[](#using-service-definitions)

```
use Duyler\DI\Definition;

$definition = new Definition(
    MyService::class,
    [
        'dependencyOne' => new AnotherService(),
        'dependencyTwo' => 'Hello, World!',
    ]
);

$container->addDefinition($definition);
```

### Service Finalization

[](#service-finalization)

```
use Duyler\DI\Attribute\Finalize;

#[Finalize]
class MyService
{
    public function finalize(): void
    {
        // Finalization logic
    }
}

// Or using container method
$container->addFinalizer(MyService::class, function (MyService $service) {
    $service->finalize();
});

// Execute finalizers
$container->finalize();
```

### Resetting Container

[](#resetting-container)

```
// Reset all services and providers
$container->reset();
```

### Getting Dependency Tree

[](#getting-dependency-tree)

```
// Get the dependency tree for a specific class
$tree = $container->getDependencyTree();
```

### Dependency Mapping

[](#dependency-mapping)

```
// Get current class mappings

$container = new Container();
$myObject = $container->get(MyClass::class);
$classMap = $container->getClassMap();
```

Advanced Features
-----------------

[](#advanced-features)

### Tagged Services

[](#tagged-services)

Tag services to group them by functionality and retrieve them as a collection:

```
use Duyler\DI\Container;
use Duyler\DI\ContainerConfig;

$container = new Container();

// Tag services at runtime
$container->tag(EventListener1::class, 'event.listener');
$container->tag(EventListener2::class, 'event.listener');
$container->tag(EventListener3::class, 'event.listener');

// Get all services with a specific tag
$listeners = $container->tagged('event.listener');
// Returns: [EventListener1, EventListener2, EventListener3]

// Tag a service with multiple tags
$container->tag(LoggerService::class, ['logger', 'monitor', 'debug']);

// Configure tags via ContainerConfig
$config = new ContainerConfig();
$config->withTag(CacheListener::class, 'event.listener');
$config->withTag(EmailListener::class, ['event.listener', 'notification']);

$container = new Container($config);
```

Common use cases:

- Event listeners and subscribers
- Middleware stacks
- Plugin systems
- Decorator chains
- Command handlers

### Service Scopes

[](#service-scopes)

Control the lifecycle of your services with scopes:

```
use Duyler\DI\Container;
use Duyler\DI\ContainerConfig;
use Duyler\DI\Scope;

$config = new ContainerConfig();
$config->withScope(TransientService::class, Scope::Transient);

$container = new Container($config);

// Singleton (default) - same instance every time
$singleton1 = $container->get(MySingletonService::class);
$singleton2 = $container->get(MySingletonService::class);
// $singleton1 === $singleton2

// Transient - new instance every time
$transient1 = $container->get(TransientService::class);
$transient2 = $container->get(TransientService::class);
// $transient1 !== $transient2
```

### Callback Factories

[](#callback-factories)

Register custom factory functions for complex service creation:

```
use Duyler\DI\Container;
use Duyler\DI\ContainerInterface;

$container = new Container();

$container->factory(MyService::class, function (ContainerInterface $c) {
    $dependency = $c->get(Dependency::class);
    return new MyService($dependency, 'custom_config_value');
});

$service = $container->get(MyService::class);
// Factory is called once, result is cached (singleton)
```

### Binding Validation

[](#binding-validation)

Bindings are automatically validated to prevent configuration errors:

```
use Duyler\DI\Container;
use Duyler\DI\ContainerConfig;
use Duyler\DI\Exception\InvalidBindingException;

$config = new ContainerConfig();

// Valid binding
$config->withBind([
    MyInterface::class => MyImplementation::class,
]);

// Invalid bindings throw InvalidBindingException:
// - Interface does not exist
// - Implementation does not exist
// - Implementation does not implement interface
// - Binding concrete class to concrete class
try {
    $config->withBind([
        ConcreteClass::class => AnotherClass::class, // Error!
    ]);
    $container = new Container($config);
} catch (InvalidBindingException $e) {
    // Handle validation error
}
```

### Compile-time Validation

[](#compile-time-validation)

Validate all dependencies before runtime to catch configuration errors early:

```
use Duyler\DI\Container;
use Duyler\DI\ContainerConfig;

$config = new ContainerConfig();
$config->withBind([
    MyInterface::class => MyImplementation::class,
    AnotherInterface::class => AnotherImplementation::class,
]);

$container = new Container($config);

// Validate all bindings without instantiating services
$errors = $container->compile();

if (empty($errors)) {
    echo "All dependencies are valid!";
} else {
    foreach ($errors as $error) {
        echo "Dependency error: $error\n";
    }
}
```

### Enhanced Error Messages

[](#enhanced-error-messages)

The container provides detailed error messages with helpful context and suggestions:

**Service Not Found with Suggestions:**

When a service cannot be found, the container suggests similar service names and provides multiple solutions.

**Circular Reference with Full Chain:**

Shows the complete dependency chain leading to the circular reference, making it easy to identify and fix the issue.

**Invalid Binding with Requirements:**

Explains why a binding is invalid and shows the requirements that must be met, along with a correct example.

**Dependency Resolution Errors with Context:**

When dependency resolution fails, shows the full dependency chain and the reason for failure with actionable solutions.

### Debug Mode

[](#debug-mode)

Enable debug mode to monitor and profile your container's dependency resolution:

```
use Duyler\DI\Container;
use Duyler\DI\ContainerConfig;

// Enable via configuration
$config = new ContainerConfig();
$config->withDebugMode(true);
$container = new Container($config);

// Or enable manually
$container = new Container();
$container->enableDebug();

// Resolve some services
$container->get(MyService::class);
$container->get(AnotherService::class);

// Get debug information
$debugInfo = $container->getDebugInfo();

// View statistics
$stats = $debugInfo->getStatistics();
echo "Total resolutions: {$stats['total_resolutions']}\n";
echo "Unique services: {$stats['unique_services']}\n";
echo "Total time: {$stats['total_time']}s\n";
echo "Peak memory: {$stats['peak_memory']} bytes\n";
echo "Average time: {$stats['avg_time']}s\n";

// Get detailed resolution data
$resolutions = $debugInfo->getResolutions();
foreach ($resolutions as $serviceId => $data) {
    echo "$serviceId: {$data['count']} times, {$data['total_time']}s total\n";
}

// Find performance bottlenecks
$slowest = $debugInfo->getSlowestServices(5);
$mostResolved = $debugInfo->getMostResolvedServices(5);

// View resolution log with timestamps
$log = $debugInfo->getResolutionLog();
foreach ($log as $entry) {
    echo "{$entry['service']}: {$entry['time']}s, {$entry['memory']} bytes, depth: {$entry['depth']}\n";
}

// Disable debug mode when not needed (improves performance)
$container->disableDebug();
```

Debug mode features:

- Track resolution count for each service
- Measure time and memory usage per service
- Calculate average resolution time
- Identify slowest services
- Find most frequently resolved services
- Complete resolution log with timestamps
- Minimal overhead when disabled

### Attribute-Based Configuration

[](#attribute-based-configuration)

Use PHP 8+ attributes to configure services declaratively:

```
use Duyler\DI\Attribute\Singleton;
use Duyler\DI\Attribute\Transient;
use Duyler\DI\Attribute\Tag;
use Duyler\DI\Attribute\Bind;

#[Singleton]
class CachedUserRepository
{
}

#[Transient]
class RequestHandler
{
}

#[Tag(['logger', 'monitor'])]
class FileLogger
{
}

#[Bind(LoggerInterface::class)]
class ConsoleLogger implements LoggerInterface
{
}

$container = new Container();
$logger = $container->get(LoggerInterface::class);
```

Attributes work seamlessly with all container features.

### Auto-Tagging by Interface

[](#auto-tagging-by-interface)

Automatically tag services by their implemented interfaces:

```
use Duyler\DI\Container;
use Duyler\DI\ContainerConfig;

interface EventListenerInterface {}

class UserListener implements EventListenerInterface {}
class OrderListener implements EventListenerInterface {}

$config = new ContainerConfig();
$config->withAutoTagging(true);

$container = new Container($config);

$container->get(UserListener::class);
$container->get(OrderListener::class);

$listeners = $container->tagged(EventListenerInterface::class);
```

Auto-tagging eliminates manual tag registration for interface-based grouping.

### Event System

[](#event-system)

Hook into container lifecycle events:

```
use Duyler\DI\Container;
use Duyler\DI\Event\ContainerEvents;

$container = new Container();

$container->on(ContainerEvents::BEFORE_RESOLVE, function ($event) {
    echo "Resolving: {$event->serviceId}\n";
});

$container->on(ContainerEvents::AFTER_RESOLVE, function ($event) {
    echo "Resolved: {$event->serviceId} in {$event->time}s\n";
});

$container->on(ContainerEvents::BEFORE_FINALIZE, function ($event) {
    echo "Starting finalization\n";
});

$container->on(ContainerEvents::AFTER_FINALIZE, function ($event) {
    echo "Finalization complete\n";
});

$service = $container->get(MyService::class);
$container->finalize();
```

Events are perfect for logging, monitoring, and debugging.

### Service Decorators

[](#service-decorators)

Wrap services with additional functionality using decorators:

```
use Duyler\DI\Container;

interface CacheInterface
{
    public function get(string $key): mixed;
}

class RedisCache implements CacheInterface
{
    public function get(string $key): mixed
    {
        return 'value from Redis';
    }
}

class CachedDecorator implements CacheInterface
{
    public function __construct(private CacheInterface $inner) {}

    public function get(string $key): mixed
    {
        echo "Cache hit check\n";
        return $this->inner->get($key);
    }
}

$container = new Container();

$container->decorate(CacheInterface::class, fn($service, $c) => new CachedDecorator($service));

$container->bind([CacheInterface::class => RedisCache::class]);
$cache = $container->get(CacheInterface::class);
```

Decorators enable aspect-oriented programming patterns like logging, caching, and validation.

Roadmap
-------

[](#roadmap)

Future planned features:

### Container Compilation

[](#container-compilation)

Pre-compile dependency resolution for maximum performance:

- Generate optimized PHP code for service instantiation
- Eliminate reflection overhead in production
- Cache compiled container configuration
- Warmup command for production deployments

Benefits: 5-10x faster service resolution.

### Lazy Loading with Proxies

[](#lazy-loading-with-proxies)

Defer service instantiation until first use:

- Generate proxy classes for services
- Automatic proxy generation for interfaces
- Transparent lazy loading without code changes
- Integration with existing scopes

Benefits: Reduced memory usage and faster bootstrap.

### Container Freeze

[](#container-freeze)

Lock container configuration after initialization:

- Prevent runtime modifications in production
- Improve security by disabling dynamic registration
- Performance optimizations for immutable containers
- Development/production mode switching

Benefits: Enhanced security and performance.

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

License
-------

[](#license)

This project is licensed under the MIT License - see the LICENSE file for details.

###  Health Score

29

—

LowBetter than 60% of packages

Maintenance48

Moderate activity, may be stable

Popularity19

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity33

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/69f18edde71f0f80540eda4e097854eddf8eb3390f38ff2ad241b9daaf622281?d=identicon)[milinsky](/maintainers/milinsky)

---

Top Contributors

[![milinsky](https://avatars.githubusercontent.com/u/17288321?v=4)](https://github.com/milinsky "milinsky (150 commits)")

### Embed Badge

![Health badge](/badges/duyler-dependency-injection/health.svg)

```
[![Health](https://phpackages.com/badges/duyler-dependency-injection/health.svg)](https://phpackages.com/packages/duyler-dependency-injection)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
