PHPackages                             denosyscore/container - 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. [PSR &amp; Standards](/categories/psr-standards)
4. /
5. denosyscore/container

ActiveLibrary[PSR &amp; Standards](/categories/psr-standards)

denosyscore/container
=====================

PSR-11 compliant dependency injection container with autowiring, contextual bindings, and service decorators for PHP 8.2+

v1.0.0(1mo ago)085MITPHPPHP ^8.2CI passing

Since Feb 14Pushed 1mo agoCompare

[ Source](https://github.com/denosyscore/container)[ Packagist](https://packagist.org/packages/denosyscore/container)[ RSS](/packages/denosyscore-container/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (7)Versions (31)Used By (5)

denosyscore/container
=====================

[](#denosyscorecontainer)

A PSR-11 compliant dependency injection container for PHP 8.2+. Supports autowiring, contextual bindings, tagged services, lazy proxies, scoped lifetimes, method injection, decorators, and built-in testing and profiling utilities.

[![PHP ^8.2](https://camo.githubusercontent.com/b5d4f7901c58ad1ddfff679966f426cc25a9354bab763846b9a7276c2feab4e0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253545382e322d626c7565)](https://camo.githubusercontent.com/b5d4f7901c58ad1ddfff679966f426cc25a9354bab763846b9a7276c2feab4e0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253545382e322d626c7565)[![License MIT](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)

Requirements
------------

[](#requirements)

- PHP ^8.2

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

[](#installation)

```
composer require denosyscore/container
```

Quick Start
-----------

[](#quick-start)

```
use Denosys\Container\Container;

$container = new Container();

// Bind an interface to a concrete class
$container->bind(LoggerInterface::class, FileLogger::class);

// Bind as a singleton
$container->singleton(CacheInterface::class, RedisCache::class);

// Resolve — dependencies are injected automatically
$logger = $container->get(LoggerInterface::class);
$cache  = $container->get(CacheInterface::class);

assert($cache === $container->get(CacheInterface::class)); // same instance
```

Autowiring
----------

[](#autowiring)

The container inspects constructor type-hints and resolves dependencies automatically. No explicit registration is needed for concrete classes:

```
class OrderService
{
    public function __construct(
        private readonly PaymentGateway $payment,
        private readonly InventoryRepository $inventory,
    ) {}
}

// PaymentGateway and InventoryRepository are built and injected automatically
$service = $container->get(OrderService::class);
```

Union-typed parameters are tried in order. Nullable and defaulted parameters fall back gracefully without throwing.

Explicit Bindings
-----------------

[](#explicit-bindings)

### bind()

[](#bind)

Register an abstract (interface or string key) to a concrete implementation or factory closure:

```
// Interface to concrete class
$container->bind(LoggerInterface::class, FileLogger::class);

// Factory closure
$container->bind(DatabaseConnection::class, function (Container $c) {
    return new DatabaseConnection(config('db.dsn'));
});
```

### singleton()

[](#singleton)

Resolved once; the same instance is returned on every subsequent call:

```
$container->singleton(CacheManager::class, RedisCacheManager::class);

$a = $container->get(CacheManager::class);
$b = $container->get(CacheManager::class);

assert($a === $b); // true
```

### instance()

[](#instance)

Register a pre-built object as a shared instance:

```
$container->instance(Config::class, new Config(['debug' => true]));
```

### alias()

[](#alias)

Create a short name for a bound abstract. The abstract must already be bound or be an instantiable class:

```
$container->bind(PaymentGateway::class, StripeGateway::class);
$container->alias('stripe', PaymentGateway::class);

$gateway = $container->get('stripe');
```

### extend()

[](#extend)

Wrap an existing binding or resolved instance with additional behavior:

```
$container->singleton(MailerInterface::class, SmtpMailer::class);

$container->extend(MailerInterface::class, function (MailerInterface $mailer, Container $c) {
    return new LoggingMailerDecorator($mailer);
});
```

Contextual Bindings
-------------------

[](#contextual-bindings)

Inject different implementations of the same interface depending on which class is requesting it:

```
$container->when(OrderController::class)
    ->needs(LoggerInterface::class)
    ->give(OrderLogger::class);

$container->when(PaymentController::class)
    ->needs(LoggerInterface::class)
    ->give(PaymentLogger::class);
```

Supply all services tagged with a given tag to a context:

```
$container->when(ReportBuilder::class)
    ->needs(FormatterInterface::class)
    ->giveTagged('report.formatters');
```

Tagged Services
---------------

[](#tagged-services)

Group related bindings under a shared tag and resolve all of them at once:

```
$container->bind(CsvFormatter::class, CsvFormatter::class);
$container->bind(JsonFormatter::class, JsonFormatter::class);

$container->tag(
    [CsvFormatter::class, JsonFormatter::class],
    'report.formatters'
);

$formatters = $container->tagged('report.formatters');
// Returns resolved instances of all tagged services

$abstracts = $container->resolveAll(FormatterInterface::class);
// Keyed by abstract name
```

A single abstract can carry multiple tags:

```
$container->tag(AuditLogger::class, ['loggers', 'auditors']);
```

Scoped Bindings
---------------

[](#scoped-bindings)

Override bindings within a bounded scope. The original bindings are automatically restored when the callable returns:

```
$result = $container->scoped([
    LoggerInterface::class => TestLogger::class,
], function () use ($container, $order) {
    // OrderService receives TestLogger inside this scope
    return $container->get(OrderService::class)->process($order);
});
// LoggerInterface is back to its original binding here
```

Lazy Loading
------------

[](#lazy-loading)

Defer resolution until the first method call. Useful for expensive services that may not be needed on every request path:

```
$proxy = $container->lazy(ReportGenerator::class);

// ReportGenerator is NOT instantiated yet

$report = $proxy->generate($data);
// Resolved on first call, then reused
```

The proxy implements `Denosys\Container\LazyProxy` and transparently forwards all method calls to the underlying instance once triggered.

Method Injection
----------------

[](#method-injection)

### call()

[](#call)

Invoke any callable with automatic injection of type-hinted parameters:

```
$result = $container->call(function (MailerInterface $mailer, string $subject = 'Hello') {
    return $mailer->send($subject);
});

// Object method
$result = $container->call([$controller, 'index']);

// Pass extra parameters — these override or supplement resolved ones
$result = $container->call([OrderService::class, 'process'], ['orderId' => 42]);
```

### callStatic()

[](#callstatic)

Call a static method with automatic injection:

```
$result = $container->callStatic(ReportGenerator::class, 'buildSummary');
```

Decorators
----------

[](#decorators)

### decorate()

[](#decorate)

Wrap a resolved service. Multiple decorators are applied in descending `$priority` order (higher runs first):

```
$container->bind(CacheInterface::class, RedisCache::class);

$container->decorate(CacheInterface::class, function (CacheInterface $cache, Container $c) {
    return new MetricsCollectingCache($cache);
}, priority: 10);

$container->decorate(CacheInterface::class, function (CacheInterface $cache, Container $c) {
    return new LoggingCache($cache);
}, priority: 5);

// Chain: RedisCache -> MetricsCollectingCache -> LoggingCache
$cache = $container->get(CacheInterface::class);
```

### middleware()

[](#middleware)

Middleware behaves like a decorator without priority ordering. Applied in registration order, after all `decorate()` layers:

```
$container->middleware(RepositoryInterface::class, function (RepositoryInterface $repo, Container $c) {
    return new CachingRepository($repo, $c->get(CacheInterface::class));
});
```

Testing Utilities
-----------------

[](#testing-utilities)

### mock()

[](#mock)

Replace a binding with a test double. Mocks take priority over all other bindings and are never decorated:

```
$mockMailer = $this->createMock(MailerInterface::class);
$mockMailer->expects($this->once())->method('send');

$container->mock(MailerInterface::class, $mockMailer);

$container->get(OrderService::class)->checkout($order);
```

### spy()

[](#spy)

Wrap a real service instance to track its resolution count and timing without replacing it:

```
$spy = $container->spy(PaymentGateway::class);

// ... exercise code that uses PaymentGateway ...

echo $spy->getResolutionCount();        // number of times resolved
echo $spy->getAverageResolutionTime();  // average ms per resolution
echo $spy->getTotalResolutionTime();    // total ms across all resolutions

$summary = $spy->getSummary();
// ['abstract' => ..., 'resolution_count' => ..., 'average_resolution_time' => ...]
```

Container Validation
--------------------

[](#container-validation)

Check for misconfigured or unresolvable bindings without instantiating anything:

```
$result = $container->validate();

if (!$result->isValid()) {
    foreach ($result->getIssues() as $issue) {
        echo $issue->getDescription();
        // "[error] Cannot resolve 'PaymentGateway' (Abstract: ...) Suggestions: ..."
    }
}

$errors   = $result->getIssuesBySeverity('error');
$warnings = $result->getIssuesBySeverity('warning');

echo $result->getSummary();
// "Validation failed. 2 issues found: 1 errors, 1 warnings."
// or: "Validation passed. No issues found."
```

`ValidationIssue` severity levels: `error`, `warning`, `info`.

Performance
-----------

[](#performance)

### getPerformanceMetrics()

[](#getperformancemetrics)

Returns a `PerformanceReport` with timing, cache ratios, and memory stats accumulated since the container was constructed:

```
$report = $container->getPerformanceMetrics();

echo $report->getSummary();
// Performance Score: 95/100
// Total Resolutions: 342
// Average Resolution Time: 0.42ms
// Cache Hit Ratio: 87.4%
// Peak Memory Usage: 12.30MB

$score  = $report->getPerformanceScore();      // 0-100
$slow   = $report->slowestResolutions;         // array abstract => ms
$top    = $report->getMostResolvedServices(5); // top 5 most-resolved services
$issues = $report->getPerformanceIssues();     // array human-readable warnings
```

### getResolutionHistory()

[](#getresolutionhistory)

Returns a ring-buffer of recent resolution records (default limit: 1000 entries):

```
$history = $container->getResolutionHistory();

foreach ($history as $entry) {
    printf(
        "%s resolved in %.2fms (mock: %s)\n",
        $entry['abstract'],
        $entry['resolution_time'],
        $entry['from_mock'] ? 'yes' : 'no'
    );
}
// Keys per entry: abstract, resolution_time, from_mock, timestamp, memory_usage
```

Lower the ring-buffer size to reduce memory overhead:

```
$container->setResolutionHistoryLimit(200);
```

License
-------

[](#license)

MIT

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance93

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 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.

###  Release Activity

Cadence

Every ~20 days

Total

5

Last Release

36d ago

Major Versions

v0.2.2 → v1.0.02026-05-04

### Community

Maintainers

![](https://www.gravatar.com/avatar/1f1c1a5b25865f0e67ca1a7d172fed5e6a7b1adb9339674341a8f1b0dbcee652?d=identicon)[deondazy](/maintainers/deondazy)

---

Top Contributors

[![deondazy](https://avatars.githubusercontent.com/u/16439886?v=4)](https://github.com/deondazy "deondazy (5 commits)")

---

Tags

phpcontainerPSR-11di containerAutowiringdependency-injectioniocservice container

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/denosyscore-container/health.svg)

```
[![Health](https://phpackages.com/badges/denosyscore-container/health.svg)](https://phpackages.com/packages/denosyscore-container)
```

###  Alternatives

[php-di/php-di

The dependency injection container for humans

2.8k53.2M1.2k](/packages/php-di-php-di)

PHPackages © 2026

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