PHPackages                             flyokai/amphp-injector - 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. [Framework](/categories/framework)
4. /
5. flyokai/amphp-injector

ActiveLibrary[Framework](/categories/framework)

flyokai/amphp-injector
======================

A dependency injector for bootstrapping object-oriented PHP applications.

v1.0.0(1mo ago)072MITPHPPHP &gt;=8.0CI failing

Since Apr 24Pushed 1mo agoCompare

[ Source](https://github.com/flyokai/amphp-injector)[ Packagist](https://packagist.org/packages/flyokai/amphp-injector)[ Docs](https://github.com/amphp/injector)[ RSS](/packages/flyokai-amphp-injector/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (14)Versions (6)Used By (2)

flyokai/amphp-injector
======================

[](#flyokaiamphp-injector)

> User docs → [`README.md`](README.md) · Agent quick-ref → [`CLAUDE.md`](CLAUDE.md) · Agent deep dive → [`AGENTS.md`](AGENTS.md)

> A dependency injection container for PHP 8.1+ with weaver-based parameter resolution, ordered compositions, attribute-driven wiring, and lifecycle management.

`flyokai/amphp-injector` is a substantially-evolved descendant of [`amphp/injector`](https://github.com/amphp/injector). The container is now driven by **weavers** (composable parameter resolvers), built around an immutable **`Application`** that owns a **`Container`** and an **`Injector`**, with first-class support for **`Composition`** collections, **PHP 8 attributes**, **lifecycle** hooks, and **alias resolution**.

> **Heads up.** Despite the package name and namespace, this is a fork. If you arrived here looking for upstream `amphp/injector`'s `Injector::make()`, `define()`, `share()`, `delegate()` API — that API is gone. Read on for what replaced it.

Features
--------

[](#features)

- **`Application`** — entry point that holds a `Container` and `Injector`, implements `Lifecycle`
- **Definition helpers** — `singleton()`, `object()`, `value()`, `factory()`, `injectableFactory()`, `compositionFactory()`, `compositionItem()`
- **Weavers** — `names()`, `types()`, `runtimeTypes()`, `automaticTypes()`, `any()` for parameter resolution
- **PHP 8 attributes** — `#[ServiceParameter]`, `#[SharedParameter]`, `#[PrivateParameter]`, `#[FactoryParameter(Class)]`
- **Compositions** — `CompositionOrdered` with topological sort via `before` / `after` / `depends`
- **Aliases** — one-way interface → implementation via `AliasResolverImpl`
- **Lifecycle** — `start()` in dependency order, `stop()` in reverse
- **Lazy proxies** — pluggable via `ProxyDefinition` (see `examples/proxy.php`)

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

[](#installation)

```
composer require flyokai/amphp-injector
```

The package's `composer.json` `replace`s `amphp/injector` so the namespace `Amp\Injector\…` resolves to this fork.

Quick start
-----------

[](#quick-start)

```
use Amp\Injector\Application;
use Amp\Injector\Definitions;
use Amp\Injector\Injector;
use function Amp\Injector\{any, arguments, names, object, singleton, value};

class MyService
{
    public function __construct(public array $config) {}
}

$definitions = (new Definitions())
    ->with(
        singleton(object(MyService::class, arguments(names()
            ->with('config', value(['key' => 'val']))
        ))),
        'my_service',
    );

$application = new Application(new Injector(any()), $definitions, 'my-app');
$application->start();

/** @var MyService $svc */
$svc = $application->getContainer()->get('my_service');

$application->stop();
```

Build flow
----------

[](#build-flow)

1. Create a `Definitions` collection containing service / object / value / factory / composition definitions.
2. Create an `Injector` with a root `Weaver` (typically `any(...)` chaining several weavers).
3. Construct `Application(injector, definitions, name, ?aliasResolver)`.
4. The `Application` calls `definition->build($injector)` for every definition and registers providers in the `Container`.
5. `application->start()` walks the providers and starts every `Lifecycle` instance in dependency order.
6. `$container->get($id)` retrieves services.
7. `application->stop()` stops in reverse order.

Definition helpers
------------------

[](#definition-helpers)

### `singleton(Definition, mustStart = false)`

[](#singletondefinition-muststart--false)

Wraps any definition to cache the instance — subsequent `get()` calls return the same object. `mustStart=true` requires the service to be started before first `get()`.

```
singleton(object(MyService::class));
singleton(object(HttpServer::class), mustStart: true);
```

### `object(string $class, ?Arguments $arguments = null)`

[](#objectstring-class-arguments-arguments--null)

Prototype factory — creates a new instance via constructor reflection every call. Wrap in `singleton()` for sharing.

```
object(Foobar::class)
object(Foobar::class, arguments(names()
    ->with('a', factory(fn() => new \stdClass()))
    ->with('b', value(42))
))
```

### `value(mixed $value)`

[](#valuemixed-value)

Wraps a literal — no construction logic.

```
value(['key' => 'val'])
value(new \Monolog\Processor\PsrLogMessageProcessor())
```

### `factory(\Closure $factory, ?Arguments $arguments = null)`

[](#factoryclosure-factory-arguments-arguments--null)

Prototype factory from a closure. The closure can accept a `ProviderContext` to inspect the injection site:

```
factory(function (ProviderContext $context): PsrLogger {
    $param = $context->getParameter(1);
    $name  = $param?->getDeclaringClass() ?? 'unknown';
    return $logger->withName($name);
})
```

### `injectableFactory(string $class, ?\Closure $factory = null, ?Arguments $arguments = null)`

[](#injectablefactorystring-class-closure-factory--null-arguments-arguments--null)

Returns a **callable** from the container, not an instance. Some parameters are pre-injected; remaining ones are passed at call time:

```
injectableFactory(BarImpl::class)
// fn(...$runtimeArgs): BarImpl => new BarImpl($injectedBaz, $injectedQux, ...$runtimeArgs)
```

### `compositionFactory(\Closure $factory, ?Definitions $itemDefinitions = null, ?Arguments $arguments = null)`

[](#compositionfactoryclosure-factory-definitions-itemdefinitions--null-arguments-arguments--null)

Creates a composition — a collection of items built from sub-definitions. The factory receives all items as named arguments.

```
compositionFactory(CompositionOrdered::selfFactory(), $itemDefinitions)
compositionFactory(MyCompositionImpl::selfFactory())
```

### `compositionItem(Definition $definition, array $before = [], array $after = [], array $depends = [])`

[](#compositionitemdefinition-definition-array-before---array-after---array-depends--)

Wraps a definition as a `CompositionItem` for use inside `CompositionOrdered`:

```
$itemDefs = definitions()
    ->with(object(CompositionItem::class, arguments()->with(names()
        ->with('after', value(['bar']))
        ->with('value', object(BazImpl::class))
    )), 'baz')
    ->with(object(CompositionItem::class, arguments()->with(names()
        ->with('before', value(['bar']))
        ->with('value', object(FooImpl::class))
    )), 'foo')
    ->with(object(CompositionItem::class, arguments()->with(names()
        ->with('value', object(BarImpl::class))
    )), 'bar');

// Final order: foo → bar → baz
```

Weavers
-------

[](#weavers)

Weavers resolve constructor / function parameters to definitions. They're chained inside `Arguments` — first match wins.

### `names(array $definitions = [])`

[](#namesarray-definitions--)

Resolves by **parameter name** — the most common weaver:

```
arguments(names()
    ->with('config', value(['key' => 'val']))
    ->with('logger', singleton(object(Logger::class)))
)
```

### `types(array $definitions = [])`

[](#typesarray-definitions--)

Resolves by **parameter type** — explicit class → definition mapping. Also indexes parent classes / interfaces.

```
types()->with(ProviderContext::class, new ProviderDefinition(new ContextProvider()))
```

### `runtimeTypes(Definitions $defs, AliasResolver $aliasResolver)`

[](#runtimetypesdefinitions-defs-aliasresolver-aliasresolver)

Resolves via **PHP 8 attributes** on parameters. Supported attributes:

AttributeResolves to`#[ServiceParameter]`shared singleton instance of the parameter's type`#[SharedParameter]`shared instance scoped to the current definition`#[PrivateParameter]`new instance per injection site`#[FactoryParameter(Class::class)]`injectable factory (callable) returning a `Class` instance```
class FooImpl
{
    public function __construct(
        #[PrivateParameter] protected Bar         $bar,
        #[SharedParameter]  protected Baz         $baz,
        #[ServiceParameter] protected Qux         $qux,
        #[FactoryParameter(Bar::class)] protected \Closure $barFactory,
    ) {}

    public function makeBar(): Bar { return ($this->barFactory)(); }
}
```

### `automaticTypes(Definitions $defs, AliasResolver $aliasResolver)`

[](#automatictypesdefinitions-defs-aliasresolver-aliasresolver)

Auto-wires by type from all registered definitions. Returns a definition only if **exactly one** matches the type — ambiguous matches return `null`.

```
$defs = definitions()
    ->with(object(Foo::class))
    ->with(object(Bar::class));

$injector = new Injector(automaticTypes($defs));
// Bar's constructor parameter of type Foo is auto-resolved.
```

### `any(Weaver ...$weavers)`

[](#anyweaver-weavers)

Tries multiple weavers in order, returns the first match. Typical setup:

```
$injector = new Injector(any(
    automaticTypes($defs, $aliasResolver),
    runtimeTypes(new Definitions(), $aliasResolver),
));
```

Alias resolution
----------------

[](#alias-resolution)

Maps interfaces to implementations via `AliasResolverImpl`. Aliases are **one-way** — requesting `Foo` yields `FooImpl`, but requesting `FooImpl` directly resolves through `FooImpl`'s own definition.

```
$aliasResolver = (new \Amp\Injector\AliasResolverImpl())
    ->with(Foo::class, FooImpl::class)
    ->with(Bar::class, BarImpl::class);

$injector = (new Injector(any(...)))
    ->withAlias($aliasResolver->alias(...));

$application = new Application($injector, $definitions, 'app', $aliasResolver);
$application->getContainer()->get(Foo::class);   // → FooImpl
```

Compositions (ordered collections)
----------------------------------

[](#compositions-ordered-collections)

`CompositionOrdered` items get topologically sorted via `before` / `after` / `depends`:

```
$items = definitions()
    ->with(object(CompositionItem::class, arguments()->with(names()
        ->with('after', value(['bar']))
        ->with('value', object(BazImpl::class))
    )), 'baz')
    ->with(object(CompositionItem::class, arguments()->with(names()
        ->with('value', object(BarImpl::class))
    )), 'bar');

$ordered = compositionFactory(CompositionOrdered::selfFactory(), $items);
```

`CompositionImpl` is the simple unordered variant. Use `selfFactory()` as the factory closure for both.

Lifecycle
---------

[](#lifecycle)

Services implementing `Lifecycle` are managed by the application:

- `start()` — called after every definition is built; walks the dependency graph; starts in dependency order
- `stop()` — called on shutdown; reverse order
- `singleton($definition, mustStart: true)` — service must be started before first `get()`
- `SingletonProvider->lazy()` — defer initialization to first `get()` instead of `start()`

Lazy proxies
------------

[](#lazy-proxies)

Pluggable via custom `Definition`s using `ocramius/proxy-manager`. See `examples/proxy.php`:

```
$definitions = (new Definitions())
    ->with(proxy(Car::class, object(Car::class)),  'car')
    ->with(proxy(V8::class,  object(V8::class)),   'engine');

$car = $container->get('car');   // Car constructor NOT called yet
$car->turnRight();                // NOW Car is constructed
```

The built-in `ProxyDefinition` currently throws `not supported yet` — provide your own `Definition` subclass.

Examples
--------

[](#examples)

The `examples/` directory contains runnable scripts for every feature:

FileDemonstrates`singleton.php`Basic singleton + value definitions`runtime.php`Attribute-driven runtime types + compositions`delegation.php`Factories and `injectableFactory``logger.php``ProviderContext` for site-aware factories`proxy.php`Lazy-loading proxy definitions`benchmark.php`Performance harnessGotchas
-------

[](#gotchas)

- **Aliases are one-way.** `Interface ⇒ Impl` lets you request the interface. Requesting `Impl` directly uses `Impl`'s own definition, not the alias.
- **Class names are normalised to lowercase** internally — don't rely on case-sensitive keys.
- **Ambiguous auto-wiring** — if two definitions share a type, `automaticTypes` returns `null`. Disambiguate with `names()` or `types()`.
- **Circular dependencies are not detected** — they cause infinite recursion. Refactor or use `lazy` singletons.
- **Containers are immutable** — every `with()` returns a clone; the `Application` holds the final reference.
- **`mustStart` singletons** — `get()` before `application->start()` throws `LifecycleException`.
- **Variadic parameters** — only supported via `injectableFactory()`. Plain `factory()` doesn't pass variadics through.
- **Built-in `ProxyDefinition` is not implemented** — see `examples/proxy.php` for a custom approach.

Differences from upstream `amphp/injector`
------------------------------------------

[](#differences-from-upstream-amphpinjector)

UpstreamThis fork`Injector::make()`, `define()`, `share()`, `delegate()`, `prepare()`gone — replaced by `Application` + `Definitions` + weavers`define()` arrays`arguments(names()->with(...))``share()``singleton(...)``alias()` (Injector method)`AliasResolverImpl` (separate object)Per-injector instance APIImmutable `Application` / `Container` / `Definitions`No compositions`Composition`, `CompositionOrdered`, `CompositionItem` first-classNo attribute-driven wiring`#[ServiceParameter]`, `#[SharedParameter]`, `#[PrivateParameter]`, `#[FactoryParameter]`No formal lifecycle`Lifecycle::start()` / `stop()` walked in dependency orderSee also
--------

[](#see-also)

- [`flyokai/application`](../application/README.md) — uses this DI as the runtime container; see also `vendor/flyokai/flyokai/docs/dependency-injection.md` for diconfig structure
- [`flyokai/composition`](../composition/README.md) — module-level topological sort (different layer than `CompositionOrdered`)
- [`flyokai/generic`](../generic/README.md) — `TunerContainer` / `ExecutionContainer` use compositions internally
- Original:

License
-------

[](#license)

MIT

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance90

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community25

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

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

Total

2

Last Release

50d ago

### Community

Maintainers

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

---

Top Contributors

[![rdlowrey](https://avatars.githubusercontent.com/u/1259291?v=4)](https://github.com/rdlowrey "rdlowrey (184 commits)")[![Danack](https://avatars.githubusercontent.com/u/1505719?v=4)](https://github.com/Danack "Danack (80 commits)")[![kelunik](https://avatars.githubusercontent.com/u/2743004?v=4)](https://github.com/kelunik "kelunik (49 commits)")[![flyokai](https://avatars.githubusercontent.com/u/247743048?v=4)](https://github.com/flyokai "flyokai (37 commits)")[![morrisonlevi](https://avatars.githubusercontent.com/u/253316?v=4)](https://github.com/morrisonlevi "morrisonlevi (29 commits)")[![staabm](https://avatars.githubusercontent.com/u/120441?v=4)](https://github.com/staabm "staabm (8 commits)")[![Alexssssss](https://avatars.githubusercontent.com/u/274893?v=4)](https://github.com/Alexssssss "Alexssssss (6 commits)")[![szepeviktor](https://avatars.githubusercontent.com/u/952007?v=4)](https://github.com/szepeviktor "szepeviktor (5 commits)")[![jeichorn](https://avatars.githubusercontent.com/u/122486?v=4)](https://github.com/jeichorn "jeichorn (4 commits)")[![ascii-soup](https://avatars.githubusercontent.com/u/627657?v=4)](https://github.com/ascii-soup "ascii-soup (4 commits)")[![bwoebi](https://avatars.githubusercontent.com/u/3154871?v=4)](https://github.com/bwoebi "bwoebi (4 commits)")[![shadowhand](https://avatars.githubusercontent.com/u/38203?v=4)](https://github.com/shadowhand "shadowhand (3 commits)")[![4d47](https://avatars.githubusercontent.com/u/729919?v=4)](https://github.com/4d47 "4d47 (2 commits)")[![Furgas](https://avatars.githubusercontent.com/u/715407?v=4)](https://github.com/Furgas "Furgas (2 commits)")[![garrettw](https://avatars.githubusercontent.com/u/84885?v=4)](https://github.com/garrettw "garrettw (2 commits)")[![lencse](https://avatars.githubusercontent.com/u/191887?v=4)](https://github.com/lencse "lencse (2 commits)")[![m6w6](https://avatars.githubusercontent.com/u/1265282?v=4)](https://github.com/m6w6 "m6w6 (2 commits)")[![thgs](https://avatars.githubusercontent.com/u/8940963?v=4)](https://github.com/thgs "thgs (2 commits)")[![vlakarados](https://avatars.githubusercontent.com/u/386678?v=4)](https://github.com/vlakarados "vlakarados (2 commits)")[![orthographic-pedant](https://avatars.githubusercontent.com/u/14522744?v=4)](https://github.com/orthographic-pedant "orthographic-pedant (1 commits)")

---

Tags

dependency-injectioniocdic

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/flyokai-amphp-injector/health.svg)

```
[![Health](https://phpackages.com/badges/flyokai-amphp-injector/health.svg)](https://phpackages.com/packages/flyokai-amphp-injector)
```

###  Alternatives

[symfony/symfony

The Symfony PHP framework

31.4k87.2M2.2k](/packages/symfony-symfony)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

751291.4k46](/packages/civicrm-civicrm-core)[rdlowrey/auryn

Auryn is a dependency injector for bootstrapping object-oriented PHP applications.

7242.3M77](/packages/rdlowrey-auryn)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k16](/packages/tempest-framework)[joomla/di

Joomla DI Package

15433.2k12](/packages/joomla-di)

PHPackages © 2026

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