PHPackages                             dakujem/wire-genie - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. dakujem/wire-genie

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

dakujem/wire-genie
==================

Autowiring Tool &amp; Dependency Provider. Wire with genie powers.

3.0(5y ago)36.4k↓37.5%1UnlicensePHPPHP ^8.0CI passing

Since May 19Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/dakujem/wire-genie)[ Packagist](https://packagist.org/packages/dakujem/wire-genie)[ RSS](/packages/dakujem-wire-genie/feed)WikiDiscussions trunk Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (16)Used By (1)

Wire Genie 🧞
============

[](#wire-genie-)

[![Tests](https://github.com/dakujem/wire-genie/actions/workflows/php-test.yml/badge.svg)](https://github.com/dakujem/wire-genie/actions/workflows/php-test.yml)[![Coverage Status](https://camo.githubusercontent.com/1949a838e4883f5c310bccc3cec45a1451fec017a62b81fe76fb3d6bf89057c8/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f64616b756a656d2f776972652d67656e69652f62616467652e7376673f6272616e63683d7472756e6b)](https://coveralls.io/github/dakujem/wire-genie?branch=trunk)

**Autowiring Tool &amp; Dependency Provider** for PSR-11 service containers. Wire with genie powers.

> 💿 `composer require dakujem/wire-genie`
>
> 📒 [Changelog](changelog.md)

What?
-----

[](#what)

A superpowered `call_user_func`? Yup! And more.

Wire Genie uses your PSR-11 service container to "magically" provide arguments (dependencies).

Allows you to:

- **invoke any callables**
- **construct any objects**

... with high level of control over the arguments. 💪

Usage
-----

[](#usage)

```
$container = new Any\Psr11\Container([
    Thing::class => new Thing(),
    MyService::class => new MyService(),
]);

$callable = function (MyService $service, Thing $thing){ ... };

class Something {
    public function __construct(MyService $service, Thing $thing) { ... }
}

$g = new Dakujem\Wire\Genie($container);

// Magic! The dependencies are resolved from the container.
$value  = $g->invoke($callable);
$object = $g->construct(Something::class);
```

That is only the basis, the process is customizable and more powerful.

For each parameter it is possible to:

- override type-hint and wire an explicit dependency (override the type-hint)
- construct missing services on demand (resolves cascading dependencies too)
- skip wiring (treat as unresolvable)
- override value (bypass the container)

```
// override type-hint(s)
$callable = function (
    #[Wire(MyService::class)] AnInterface $service,
    #[Wire(Thing::class)] $thing
){ ... };
$value  = $g->invoke($callable);

// construct object(s) if not present in the container
$callable = function (
    #[Hot] Something $some,
    #[Make(Thing::class)] $thing
){ ... };
$value  = $g->invoke($callable);

// provide arguments for scalar-type, no-type and otherwise unresolvable parameters
$callable = function (string $question, MyService $service, int $answer){ ... };
$g->invoke(
    $callable,
    'The Ultimate Question of Life, the Universe, and Everything.',
     42,
);
$g->invoke(
    $callable,
    answer: 42,
    question: 'The Ultimate Question of Life, the Universe, and Everything.',
);

// skip wiring for a parameter...
$callable = function (#[Skip] MyService $service){ ... };
$g->invoke($callable, new MyService(...)); // ...and provide your own argument(s)
```

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

[](#how-it-works)

There are two primary methods:

```
Genie::invoke(  callable $target, ...$pool );
Genie::construct( string $target, ...$pool );
```

... where the variadic `$pool` is a list of values that will be used for unresolvable parameters.

The resolution algorithm works like the following. If any step succeeds, the rest is skipped.
For each parameter...

1. If the parameter name matches a *named argument* from the pool, use it.
2. If `#[Skip]` hint is present, skip steps 3-6 and treat the parameter as unresolvable.
3. If a `#[Wire(Identifier::class)]` hint (attribute) is present, resolve the hinted identifier using the container.
4. Resolve the type-hinted identifier using the container.
5. If `#[Hot]` hint is present, attempt to create the type-hinted class. Resolve cascading dependencies.
6. If `#[Make(Name::class)]` hint is present, attempt to create the hinted class. Resolve cascading dependencies.
7. When a parameter is unresolvable, try filling in an argument from the pool.
8. If a default parameter value is defined, use it.
9. If the parameter is nullable, use `null`.
10. Fail utterly.

### Hints / attributes

[](#hints--attributes)

As you can see, the algorithm uses native attributes as hints to control the wiring.

`#[Wire(Identifier::class)]` tells Genie to try to wire the service registered as `Identifier` from the container
`#[Wire('identifier')]` tells Genie to try to wire service with `'identifier'` identifier from the container
`#[Hot]` tells Genie to try to create the type-hinted class (works with union types too)
`#[Make(Service::class, 42, 'argument')]` tells Genie to try to create `Service` class using `42` and `'argument'` as the argument pool for the construction
`#Skip` tells Genie not to use the container at all

`Hot` and `Make` work recursively, their constructor dependencies will be resolved from the container or created on the fly too.

What can it be used for?
------------------------

[](#what-can-it-be-used-for)

- middleware / pipeline *dispatchers*
- asynchronous *job execution*
    - supplying dependencies after a job is deserialized from a queue
- generic *factories* that create instances with varying dependencies
- *method dependency injection*
    - for controllers, where dependencies are wired at runtime

**Examples**

- [asynchronous job execution](examples/jobExecute.php)

### A word of caution

[](#a-word-of-caution)

Fetching services from the service container on-the-fly might solve an edge case in certain implementations where dependency injection boilerplate can not be avoided or reduced in a different way.

It is also the only way to invoke callables with dependencies not known at the time of compilation.

Normally, however, you want to wire your dependencies when building your app's service container.

> Disclaimer 🤚
>
> Improper use of this package might break established IoC principles and degrade your dependency injection container to a service locator, so use the package with caution.
>
> Remember, it is always better to inject a service into a working class, then to fetch the service from within the working class (this is called "Inversion of Control", "IoC").

Integration
-----------

[](#integration)

As with many other third-party libraries, you should consider wrapping code using Wire Genie into a helper class with methods like the following one:

```
/**
 * Invokes a callable resolving its type-hinted arguments,
 * filling in the unresolved arguments from the static argument pool.
 * Returns the callable's return value.
 * Also allows to create objects passing in a class name.
 */
public function call(callable|string $target, ...$pool): mixed
{
    return Genie::employ($this->container)($target, ...$pool);
}
```

This adds a tiny layer for flexibility, in case you decide to tweak the way you wire dependencies later on.

Static provisioning
-------------------

[](#static-provisioning)

`Genie::provide()` can be used to provision a callable with a fixed list of services without using reflection.

```
$factory = function( Dependency $dep1, OtherDependency $dep2 ): MyObject {
    return new MyObject($dep1, $dep2);
};
$object = $g->provide( Dependency::class, OtherDependency::class )->invoke($factory);
```

Limiting access to services
---------------------------

[](#limiting-access-to-services)

You can limit the services accessible through `Genie` by using a filtering proxy `Limiter`:

```
$repoGenie = new Dakujem\Wire\Genie(
    new Dakujem\Wire\Limiter($container, [
        RepositoryInterface::class,
        // you may whitelist multiple classes or interfaces
    ])
);
```

The proxy uses the `instanceof` type operator and throws if the requested service does not match at least one of the whitelisted classes or interface names.

Customization
-------------

[](#customization)

A custom *strategy* can be inserted into `Genie`, and the default `AttributeBasedStrategy` allows for customization of the resolver mechanism, thus providing ultimate configurability.

Compatibility
-------------

[](#compatibility)

Framework agnostic. Any PSR-11 container can be used.

Wonderful lamp
--------------

[](#wonderful-lamp)

```
// If we happen to find a magical lamp...
$lamp = new Dakujem\Wire\Lamp($container);

// we can rub it, and a genie might come out!
$genie = $lamp->rub();

// My wish number one is...
$genie->construct(Palace::class);
```

Flying carpet
-------------

[](#flying-carpet)

We've already got a lamp 🪔 and a genie 🧞 ... so?

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

[](#installation)

💿 `composer require dakujem/wire-genie`

> Never heard of [Composer](https://getcomposer.org)? Go get it!

Testing
-------

[](#testing)

Run unit tests using the following command:

`$` `composer test`
or
`$` `php vendor/phpunit/phpunit/phpunit tests`

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

[](#contributing)

Ideas, feature requests and other contribution is welcome. Please send a PR or create an issue.

---

Now go, do some wiring!

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance50

Moderate activity, may be stable

Popularity25

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity68

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

Recently: every ~0 days

Total

12

Last Release

1972d ago

Major Versions

1.1.1 → 2.0.0-alpha12020-12-06

v2.99.x-dev → 3.02020-12-23

PHP version history (3 changes)1.0PHP &gt;=7.2

1.1.1PHP ^7.2 || ^8.0

2.99PHP ^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/0bd7fa945013e9c0dcd65693575276bf5fcb9b9de13e1123e9f2c4a0a4c0fb6b?d=identicon)[dakujem](/maintainers/dakujem)

---

Top Contributors

[![dakujem](https://avatars.githubusercontent.com/u/443067?v=4)](https://github.com/dakujem "dakujem (90 commits)")

---

Tags

dependency-injectionservice-locator

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/dakujem-wire-genie/health.svg)

```
[![Health](https://phpackages.com/badges/dakujem-wire-genie/health.svg)](https://phpackages.com/packages/dakujem-wire-genie)
```

###  Alternatives

[symfony/dependency-injection

Allows you to standardize and centralize the way objects are constructed in your application

4.2k431.1M7.5k](/packages/symfony-dependency-injection)[illuminate/contracts

The Illuminate Contracts package.

705122.9M10.1k](/packages/illuminate-contracts)[illuminate/container

The Illuminate Container package.

31178.1M2.0k](/packages/illuminate-container)[ecotone/ecotone

Supporting you in building DDD, CQRS, Event Sourcing applications with ease.

558549.8k17](/packages/ecotone-ecotone)[civicrm/civicrm-core

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

728272.9k20](/packages/civicrm-civicrm-core)[internal/dload

Downloads binaries.

98142.7k10](/packages/internal-dload)

PHPackages © 2026

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