PHPackages                             marcosdipaolo/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. marcosdipaolo/container

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

marcosdipaolo/container
=======================

A production-ready PSR-11 dependency injection container with automatic wiring, lifecycle management, and circular dependency detection.

1.1.0(2mo ago)0451MITPHPPHP ^8.2CI passing

Since Aug 26Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/marcosdipaolo/container)[ Packagist](https://packagist.org/packages/marcosdipaolo/container)[ RSS](/packages/marcosdipaolo-container/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (2)Dependencies (7)Versions (4)Used By (1)

PSR-11 Dependency Injection Container
=====================================

[](#psr-11-dependency-injection-container)

A production-ready, lightweight PSR-11 compliant dependency injection container for PHP with automatic constructor wiring, lifecycle management, and circular dependency detection.

Features
--------

[](#features)

✅ **PSR-11 Compliant** - Implements the standard `ContainerInterface`
✅ **Automatic Wiring** - Resolves constructor dependencies without configuration
✅ **Lifecycle Management** - Singleton, transient, and factory bindings
✅ **Circular Dependency Detection** - Catches infinite dependency loops at resolution time
✅ **Reflection Caching** - Optimized performance for repeated resolutions
✅ **Type Safety** - Comprehensive error messages with actionable guidance
✅ **Fully Tested** - Extensive PHPUnit test suite with high coverage
✅ **Static Analysis** - PHPStan level 10 compliant

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

[](#installation)

```
composer require marcosdipaolo/container
```

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

[](#quick-start)

```
use MDP\Container\Container;

$container = new Container();

// Automatic wiring
$myService = $container->get(MyService::class);

// Register bindings
$container->singleton(DatabaseInterface::class, MySQLDatabase::class);
$container->transient(Logger::class, FileLogger::class);
$container->factory('timestamp', fn() => time());

// Get instances
$db = $container->get(DatabaseInterface::class);
$logger = $container->get(Logger::class);
$time = $container->get('timestamp');
```

Usage Guide
-----------

[](#usage-guide)

### Automatic Wiring

[](#automatic-wiring)

The container can automatically resolve classes by analyzing their constructor dependencies:

```
class UserRepository
{
    public function __construct(private DatabaseConnection $db) {}
}

class UserService
{
    public function __construct(private UserRepository $repo) {}
}

// No registration needed!
$userService = $container->get(UserService::class);
// All dependencies are automatically injected
```

### Lifecycle Management

[](#lifecycle-management)

#### Singleton Binding

[](#singleton-binding)

Returns the same instance every time:

```
$container->singleton(Logger::class, FileLogger::class);

$logger1 = $container->get(Logger::class);
$logger2 = $container->get(Logger::class);

assert($logger1 === $logger2); // True
```

#### Transient Binding

[](#transient-binding)

Creates a new instance every time:

```
$container->transient(Request::class, HttpRequest::class);

$req1 = $container->get(Request::class);
$req2 = $container->get(Request::class);

assert($req1 !== $req2); // True - different instances
```

#### Factory Binding

[](#factory-binding)

Custom resolution logic with full control:

```
$container->factory('config', function(Container $container) {
    return new Config(getenv('CONFIG_PATH'));
});

// Created fresh every time via the factory function
$config = $container->get('config');
```

### Interface Binding

[](#interface-binding)

Bind interfaces to concrete implementations:

```
interface CacheStoreInterface {}
class RedisCache implements CacheStoreInterface {}

$container->singleton(CacheStoreInterface::class, RedisCache::class);

$cache = $container->get(CacheStoreInterface::class);
assert($cache instanceof RedisCache); // True
```

### Custom Resolution

[](#custom-resolution)

Use factory functions for complex setup:

```
$container->set('pdo', function(Container $container) {
    return new PDO('sqlite::memory:');
});

// With more control - access other services
$container->set(UserRepository::class, function(Container $container) {
    $db = $container->get('pdo');
    $logger = $container->get(Logger::class);
    return new UserRepository($db, $logger);
});
```

API Reference
-------------

[](#api-reference)

### Constructor

[](#constructor)

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

### Methods

[](#methods)

#### `set(string $id, callable|string $concrete, string $lifecycle = 'transient'): void`

[](#setstring-id-callablestring-concrete-string-lifecycle--transient-void)

Register a binding with optional lifecycle:

```
$container->set('name', ConcreteClass::class);
$container->set('factory', fn($c) => new Thing(), 'transient');
```

#### `singleton(string $id, callable|string $concrete): void`

[](#singletonstring-id-callablestring-concrete-void)

Register a singleton binding (single instance):

```
$container->singleton(Database::class, MySQLDatabase::class);
```

#### `transient(string $id, callable|string $concrete): void`

[](#transientstring-id-callablestring-concrete-void)

Register a transient binding (new instance each time):

```
$container->transient(Request::class, HttpRequest::class);
```

#### `factory(string $id, callable $factory): void`

[](#factorystring-id-callable-factory-void)

Register a factory binding:

```
$container->factory('timestamp', fn($c) => time());
```

#### `get(string $id): mixed`

[](#getstring-id-mixed)

Resolve a service from the container:

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

Throws `NotFoundException` if the service cannot be resolved.

#### `has(string $id): bool`

[](#hasstring-id-bool)

Check if a service is registered:

```
if ($container->has('config')) {
    $config = $container->get('config');
}
```

#### `resolve(string $id): object`

[](#resolvestring-id-object)

Resolve a class by name without prior registration:

```
$service = $container->resolve(MyService::class);
// All constructor dependencies are wired automatically
```

Throws `NotFoundException` if the class doesn't exist.
Throws `ContainerException` if the class cannot be instantiated.

#### `clearSingletons(): void`

[](#clearsingletons-void)

Clear all cached singleton instances:

```
$container->clearSingletons();
// Next get() will create fresh instances
```

Useful for testing.

#### `clearReflectionCache(): void`

[](#clearreflectioncache-void)

Clear cached reflection metadata:

```
$container->clearReflectionCache();
```

Useful for debugging or dynamic code generation scenarios.

Error Handling
--------------

[](#error-handling)

The container provides detailed error messages to help with debugging:

### Missing Type Hints

[](#missing-type-hints)

```
class Service
{
    public function __construct($dependency) {} // No type hint!
}

$container->get(Service::class);
// ContainerException: Cannot resolve "Service" - constructor parameter
// "dependency" is missing a type hint. Add a type declaration or use
// a factory function for explicit wiring.
```

**Solution:** Add a type hint or use a factory function.

### Union Types

[](#union-types)

```
class Service
{
    public function __construct(TypeA|TypeB $dependency) {}
}

$container->get(Service::class);
// ContainerException: Cannot resolve "Service" - constructor parameter
// "dependency" has a union type. Union types are ambiguous for automatic
// resolution. Use a factory function instead.
```

**Solution:** Use a factory function to explicitly choose which type to inject.

### Circular Dependencies

[](#circular-dependencies)

```
class ServiceA { public function __construct(ServiceB $b) {} }
class ServiceB { public function __construct(ServiceA $a) {} }

$container->get(ServiceA::class);
// CircularDependencyException: Circular dependency detected:
// ServiceA -> ServiceB -> ServiceA
```

**Solution:** Break the circular dependency or use lazy-loading / property injection.

### Built-in Type Without Default

[](#built-in-type-without-default)

```
class Service
{
    public function __construct(string $name) {} // No default value
}

$container->get(Service::class);
// ContainerException: Cannot resolve "Service" - constructor parameter
// "name" is a builtin type with no default value. Use a factory function
// for custom wiring.
```

**Solution:** Provide a default value or use a factory function.

Testing
-------

[](#testing)

The package includes a comprehensive test suite:

```
# Run tests
composer test

# Generate coverage report
composer test:coverage

# Static analysis
composer phpstan

# Code quality checks
composer lint
composer lint:fix

# Code modernization suggestions
composer rector:check
composer rector:fix
```

Performance Considerations
--------------------------

[](#performance-considerations)

### Reflection Caching

[](#reflection-caching)

The container caches reflection metadata after first resolution:

```
// First call: reflection overhead
$service = $container->get(Service::class);

// Subsequent calls: cached reflection
$service2 = $container->get(Service::class);
```

Clear the cache if working with dynamically generated classes:

```
$container->clearReflectionCache();
```

### Singleton Pattern

[](#singleton-pattern)

Use singletons for expensive-to-create services:

```
// Good - database connection created once
$container->singleton(PDOConnection::class, function($c) {
    return new PDO('mysql:host=localhost', 'user', 'pass');
});

// Poor - creates new connection for every request
$container->transient(PDOConnection::class, PDOConnection::class);
```

PSR-11 Compliance
-----------------

[](#psr-11-compliance)

This container implements the `Psr\Container\ContainerInterface` and follows PSR-11 standards:

- Implements `get(string $id): mixed`
- Implements `has(string $id): bool`
- Throws `Psr\Container\NotFoundExceptionInterface` when services aren't found
- Throws `Psr\Container\ContainerExceptionInterface` for container errors

Best Practices
--------------

[](#best-practices)

1. **Use constructor dependency injection** - Prefer constructor parameters over setter injection
2. **Type hint everything** - Enable automatic wiring with proper type hints
3. **Use interfaces for bindings** - Makes code more testable and maintainable
4. **Register at bootstrap** - Set up bindings in a single bootstrap file
5. **Use factories for complex logic** - When automatic wiring isn't enough
6. **Avoid circular dependencies** - Refactor to break cycles or use lazy-loading
7. **Test with `clearSingletons()`** - Reset state between tests

License
-------

[](#license)

MIT License - see [LICENSE](LICENSE) file

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

[](#contributing)

Contributions are welcome! Please ensure all tests pass and code meets PHPStan level max:

```
composer test
composer phpstan
composer lint:fix
```

---

**Need Help?** Check the [test suite](tests/) for more examples and edge cases.

###  Health Score

43

—

FairBetter than 90% of packages

Maintenance84

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity62

Established project with proven stability

 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 ~1317 days

Total

2

Last Release

81d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/22824656?v=4)[marcosdipaolo](/maintainers/marcosdipaolo)[@marcosdipaolo](https://github.com/marcosdipaolo)

---

Top Contributors

[![marcosdipaolo](https://avatars.githubusercontent.com/u/22824656?v=4)](https://github.com/marcosdipaolo "marcosdipaolo (9 commits)")

---

Tags

containerPSR-11dependency-injectiondiioc

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[php-di/php-di

The dependency injection container for humans

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

A flexible dependency injection container

20268.4k6](/packages/slince-di)

PHPackages © 2026

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