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

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

pwm/sfw-container
=================

A simple Container that ensures a cycle-free dependency graph

3.0.0(7y ago)52.5kMITPHPPHP &gt;=7.1.0

Since Apr 27Pushed 7y ago1 watchersCompare

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

READMEChangelogDependencies (4)Versions (6)Used By (0)

SFW Container
=============

[](#sfw-container)

[![Build Status](https://camo.githubusercontent.com/f27b9087afd19ae00da4000b58b8d60311789e79795eb41f31e994dcf1a70e6f/68747470733a2f2f7472617669732d63692e6f72672f70776d2f7366772d636f6e7461696e65722e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/pwm/sfw-container)[![codecov](https://camo.githubusercontent.com/ff0e5eca75372ee3b94174131632a464488c8a4c2efc17dc8b891670012440d8/68747470733a2f2f636f6465636f762e696f2f67682f70776d2f7366772d636f6e7461696e65722f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/pwm/sfw-container)[![Maintainability](https://camo.githubusercontent.com/f9108411fa36a3cfd7ee7f16053ccaec860a3b5c75bbc2bf85927180e74ba28d/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f65396466383333343939623738383565306632312f6d61696e7461696e6162696c697479)](https://codeclimate.com/github/pwm/sfw-container/maintainability)[![Test Coverage](https://camo.githubusercontent.com/6680c86201d362bd1905545a64c30ec3a6e135454083cc176d540562670aa4cb/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f65396466383333343939623738383565306632312f746573745f636f766572616765)](https://codeclimate.com/github/pwm/sfw-container/test_coverage)[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](https://opensource.org/licenses/MIT)

A minimalistic DI container with cycle detection, cacheable instance resolution and dynamic loading.

Table of Contents
-----------------

[](#table-of-contents)

- [Why](#why)
- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
- [How it works](#how-it-works)
- [Tests](#tests)
- [Changelog](#changelog)
- [Licence](#licence)

Why
---

[](#why)

There are many DI containers out there. My design goals were:

- Minimalism
- Cycle detection in the dependency graph
- Instance caching by default
- Dynamic loading

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

[](#requirements)

PHP 7.1+

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

[](#installation)

```
composer require pwm/sfw-container

```

Usage
-----

[](#usage)

Basic usage:

```
// Have some classes, some of them depend on others
class A { public function __construct(int $x) {} }
class B { public function __construct(string $s) {} }
class C { public function __construct(A $a, B $b) {} }

// Create a container
$c = new Container();

// Add resolver functions to the container that will instantiate your classes
$c->add(A::class, function (): A {
    return new A(1);
});
$c->add(B::class, function (): B {
    return new B('x');
});

// Resolving from within resolvers is easy as the Container is passed to the functions as the 1st parameter
$c->add(C::class, function (Container $c): C {
    return new C(
        $c->resolve(A::class),
        $c->resolve(B::class)
    );
});

// Resolve your classes
assert($c->resolve(A::class) instanceof A);
assert($c->resolve(B::class) instanceof B);
assert($c->resolve(C::class) instanceof C);
```

Cycle detection:

```
// X depends on Y and Y depends on X ...
class X { public function __construct(Y $y) {} }
class Y { public function __construct(X $x) {} }

$c = new Container();

$c->add(X::class, function (Container $c): X {
    return new X($c->resolve(Y::class));
});
$c->add(Y::class, function (Container $c): Y {
    return new Y($c->resolve(X::class));
});

try {
    $c->resolve(X::class);
} catch (CycleDetected $e) {
    assert('X -> Y -> X' === $e->getMessage());
}
```

Factory vs. cached instances:

```
// Simple class that saves a timestamp
class TS {
    private $timestamp;
    public function __construct(int $timestamp) {
        $this->timestamp = $timestamp;
    }
    public function getTimestamp(): int {
        return $this->timestamp;
    }
}

$c = new Container();

// Add our TS class both cached and as a factory (using different keys)
$c->add('cachedTS', function (): TS {
    return new TS(time());
});
$c->factory('factoryTS', function (): TS {
    return new TS(time());
});

// Get an instance for both
$cTS = $c->resolve('cachedTS'); // instantiate and cache
$fTS = $c->resolve('factoryTS'); // just instantiate

// Wait a sec ...
sleep(1);

// For the cached ones timestamps will match
assert($cTS->getTimestamp() === $c->resolve('cachedTS')->getTimestamp());

// Factory instantiates again, hence timestamps will differ
assert($fTS->getTimestamp() !== $c->resolve('factoryTS')->getTimestamp());
```

Dynamic loading:

```
interface Reader {
    public function read(): string;
}
class XmlReader implements Reader {
    public function read(): string {
        return 'Reading Xml...';
    }
}
class JsonReader implements Reader {
    public function read(): string {
        return 'Reading Json...';
    }
}

$c = new Container();

// Reader's resolver has to be added via factory otherwise
// it will be bound to whatever it first resolves to
$c->factory(Reader::class, function (Container $c, string $strategy): Reader {
    switch ($strategy) {
        case 'xml':
            return new XmlReader();
        case 'json':
            return new JsonReader();
        default:
            throw new RuntimeException(sprintf('No reader found for %s', $strategy));
    }
});

assert('Reading Xml...' === $c->resolve(Reader::class, 'xml')-> read());
assert('Reading Json...' === $c->resolve(Reader::class, 'json')-> read());

try {
    $c->resolve(Reader::class, 'csv');
} catch (RuntimeException $e) {
    assert('No reader found for csv' === $e->getMessage());
}
```

How it works
------------

[](#how-it-works)

A container is just a map where keys are ids of classes defined by us and values are functions, called resolvers, that know how to instantiate these classes. Resolving a class simply means executing its resolver which will return an instance of the class. It's good practice to use full class names namepsace included as ids but we are free to use any string we like.

All resolvers get the container itself as their first argument which makes it easy to resolve from within a resolver, making the resolution process recursive. This is very useful as classes may have other classes as dependencies.

While we are free to build any dependency graph we like, the resolution process will stop when it encounters a cycle while traversing it. This ensures that only acyclic graphs (ie. DAGs) are handled and saves us from blowing the callstack.

The container caches resolved instances by default meaning that any subsequent resolution will return the same instance. This is good and usually what we want. However, if a resolver was added via the `factory()` method then every resolution will return a new instance of that class.

We can also pass extra parameters to resolvers. This, combined with `factory()`, makes it possible to implement dynamic loading, ie. to instantiate an interface in various different ways. An example of this would be what is known as the Strategy pattern, ie. using runtime information, eg. a user supplied CLI parameter, to instantiate the appropriate implementation of some interface.

Tests
-----

[](#tests)

```
$ vendor/bin/phpunit
$ composer phpcs
$ composer phpstan
$ composer infection

```

Changelog
---------

[](#changelog)

[Click here](changelog.md)

Licence
-------

[](#licence)

[MIT](LICENSE)

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity20

Limited adoption so far

Community7

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

Total

5

Last Release

2771d ago

Major Versions

1.1.0 → 2.0.02018-06-15

2.1.0 → 3.0.02018-10-12

### Community

Maintainers

![](https://www.gravatar.com/avatar/361d01dea838dfee1327e7c6e803e7f53ae92b48d6971bcaeca43d3d49504c19?d=identicon)[pwm](/maintainers/pwm)

---

Top Contributors

[![pwm](https://avatars.githubusercontent.com/u/195513?v=4)](https://github.com/pwm "pwm (22 commits)")

---

Tags

containerdagdependency-injectionsfwcontainerdependency-injectionsfwDAG

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[pimple/pimple

Pimple, a simple Dependency Injection Container

2.7k130.5M1.4k](/packages/pimple-pimple)[php-di/php-di

The dependency injection container for humans

2.8k48.9M994](/packages/php-di-php-di)[aura/di

A serializable dependency injection container with constructor and setter injection, interface and trait awareness, configuration inheritance, and much more.

356968.3k58](/packages/aura-di)[acclimate/container

Provides adapters for various third-party service containers.

219390.6k15](/packages/acclimate-container)[mrclay/props-dic

Props is a simple DI container that allows retrieving values via custom property and method names

3611.7M3](/packages/mrclay-props-dic)[slince/di

A flexible dependency injection container

20260.4k6](/packages/slince-di)

PHPackages © 2026

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