PHPackages                             tobento/service-resolver - 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. tobento/service-resolver

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

tobento/service-resolver
========================

A resolver for building PHP applications.

2.0.2(7mo ago)02812MITPHPPHP &gt;=8.4

Since Jan 15Pushed 7mo ago1 watchersCompare

[ Source](https://github.com/tobento-ch/service-resolver)[ Packagist](https://packagist.org/packages/tobento/service-resolver)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-service-resolver/feed)WikiDiscussions 2.x Synced 1mo ago

READMEChangelog (5)Dependencies (5)Versions (6)Used By (2)

Resolver Service
================

[](#resolver-service)

The Resolver Service is an abstraction layer of PSR-11 container.

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

[](#table-of-contents)

- [Getting started](#getting-started)
    - [Requirements](#requirements)
    - [Highlights](#highlights)
- [Documentation](#documentation)
    - [Implementations](#implementations)
    - [Resolver Factory](#resolver-factory)
    - [Resolver](#resolver)
        - [PSR-11](#psr-11)
        - [Autowiring](#autowiring)
        - [Definitions](#definitions)
        - [Make](#make)
        - [Call](#call)
        - [On](#on)
            - [Replace objects](#replace-objects)
            - [Modify objects](#modify-objects)
            - [Construct objects](#construct-objects)
            - [Call Methods](#call-methods)
            - [Using Once](#using-once)
            - [Using Prototype](#using-prototype)
            - [Using Instanceof](#using-instanceof)
            - [Using Priority](#using-priority)
        - [Rule](#rule)
        - [Container](#container)
- [Credits](#credits)

---

Getting started
===============

[](#getting-started)

Add the latest version of the resolver service project running this command.

```
composer require tobento/service-resolver

```

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

[](#requirements)

- PHP 8.4 or greater

Highlights
----------

[](#highlights)

- Framework-agnostic, will work with any project
- Decoupled design
- Autowiring

Documentation
=============

[](#documentation)

Implementations
---------------

[](#implementations)

Currently, there are the following implementations:

- [service-resolver-container](https://github.com/tobento-ch/service-resolver-container)

Resolver Factory
----------------

[](#resolver-factory)

```
use Tobento\Service\ResolverContainer\ResolverFactory;
use Tobento\Service\Resolver\ResolverFactoryInterface;
use Tobento\Service\Resolver\ResolverInterface;

$resolverFactory = new ResolverFactory();

var_dump($resolverFactory instanceof ResolverFactoryInterface);
// bool(true)

// create resolver
$resolver = $resolverFactory->createResolver();

var_dump($resolver instanceof ResolverInterface);
// bool(true)
```

Resolver
--------

[](#resolver)

### PSR-11

[](#psr-11)

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo {}

$resolver = new ResolverFactory()->createResolver();

var_dump($resolver->has(Bar::class));
// bool(false)

var_dump($resolver->get(Foo::class));
// object(Foo)#5 (0) { }
```

### Autowiring

[](#autowiring)

The resolver resolves any dependencies by autowiring, except build-in parameters needs a [definition](#definitions) to be resolved.

On union types parameter, the first resolvable parameter gets used if not set by definiton.

### Definitions

[](#definitions)

**By providing the resolved object:**

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo
{
    public function __construct(
        protected string $name
    ) {}
}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(Foo::class, new Foo('value'));

var_dump($resolver->get(Foo::class));
// object(Foo)#3 (1) { ["name":protected]=> string(5) "value" }
```

**By defining the missing parameters:**

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo
{
    public function __construct(
        protected string $name
    ) {}
}

$resolver = new ResolverFactory()->createResolver();

// By the construct method:
$resolver->set(Foo::class)->construct('value');

// By the with method using parameter name:
$resolver->set(Foo::class)->with(['name' => 'value']);

// By the with method using parameter position:
$resolver->set(Foo::class)->with([0 => 'value']);

var_dump($resolver->get(Foo::class));
// object(Foo)#9 (1) { ["name":protected]=> string(5) "value" }
```

**By using a closure:**

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo
{
    public function __construct(
        protected string $name
    ) {}
}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(Foo::class, function($container) {
    return new Foo('value');
});

var_dump($resolver->get(Foo::class));
// object(Foo)#8 (1) { ["name":protected]=> string(5) "value" }
```

**You might configure which implementation to use:**

```
$resolver->set(BarInterface::class, Bar::class);
```

**Defining method calls:** You will need only to define build-in parameters as others get autowired if you want to.

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo
{
    protected array $called = [];

    public function index(Bar $bar, string $name)
    {
        $this->called[] = [$bar, $name];
    }
}

class Bar {}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(Foo::class)->callMethod('index', ['name' => 'value']);

$resolver->set(Foo::class)->callMethod('index', [1 => 'value']);

$foo = $resolver->get(Foo::class);
```

**Prototype Definition:**

You might declare the defintion as prototype, meaning returning always a new instance.

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo {}
class Bar {}

$resolver = (new ResolverFactory())->createResolver();

$resolver->set(Foo::class)->prototype();

$resolver->set(Bar::class, function() {
    return new Bar();
})->prototype();

var_dump($resolver->get(Foo::class) === $resolver->get(Foo::class));
// bool(false)

var_dump($resolver->get(Bar::class) === $resolver->get(Bar::class));
// bool(false)
```

### Make

[](#make)

The make() method works like get() except it will resolve the entry every time it is called.

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo
{
    public function __construct(
        private Bar $bar,
        private string $name
    ) {}
}

class Bar {}

$resolver = new ResolverFactory()->createResolver();

$foo = $resolver->make(Foo::class, ['name' => 'value']);
```

### Call

[](#call)

For more detail visit: [service-autowire#call](https://github.com/tobento-ch/service-autowire#call)

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class Foo
{
    public function index(Bar $bar, string $name): string
    {
        return $name;
    }
}

class Bar {}

$resolver = new ResolverFactory()->createResolver();

$name = $resolver->call([Foo::class, 'index'], ['name' => 'value']);

var_dump($name);
// string(5) "value"
```

### On

[](#on)

With the **on** method, you may replace, modify or construct objects.

#### Replace objects

[](#replace-objects)

**Replace object**

You may replace the resolved object by simply declare a class:

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class AdminUser {}
class GuestUser {}

$resolver = new ResolverFactory()->createResolver();

$resolver->on(AdminUser::class, GuestUser::class);

$user = $resolver->get(AdminUser::class);

var_dump($user);
// object(GuestUser)#9 (0) { }
```

**Replace object by using a callable**

You may replace the resolved object by using a callable. The first argument will always be the resolved object, but you can typehint any other object you may need next.

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class AdminUser {}
class GuestUser {}

$resolver = new ResolverFactory()->createResolver();

$resolver->on(AdminUser::class, function($user) {
    return new GuestUser();
});

// with typehint:
$resolver->on(AdminUser::class, function($user, GuestUser $guest) {
    return $guest;
});

$user = $resolver->get(AdminUser::class);

var_dump($user);
// object(GuestUser)#17 (0) { }
```

#### Modify objects

[](#modify-objects)

**Modify object by using a callable**

You may modify the resolved object by using a callable. The first argument will always be the resolved object, but you can typehint any other object you may need next.

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class AdminUser {}
class GuestUser {}

$resolver = new ResolverFactory()->createResolver();

$resolver->on(AdminUser::class, function($user) {
    // modify $user
});

$user = $resolver->get(AdminUser::class);

var_dump($user);
// object(AdminUser)#9 (0) { }
```

#### Construct objects

[](#construct-objects)

**Construct object by providing an array**

You may wish to inject different implementations into each class or inject any primitive values.

```
use Tobento\Service\ResolverContainer\ResolverFactory;

interface UserInterface {}
class GuestUser implements UserInterface {}
class AdminUser implements UserInterface {}

class ServiceFoo {
    public function __construct(
        protected UserInterface $user
    ) {}
}

class ServiceBar {
    public function __construct(
        protected UserInterface $user
    ) {}
}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(UserInterface::class, GuestUser::class);

$resolver->on(ServiceFoo::class, ['user' => AdminUser::class]);

var_dump($resolver->get(ServiceFoo::class));
// object(ServiceFoo)#14 (1) { ["user":protected]=> object(AdminUser)#11 (0) { } }

var_dump($resolver->get(ServiceBar::class));
// object(ServiceBar)#9 (1) { ["user":protected]=> object(GuestUser)#13 (0) { } }
```

**Construct object by using a callable returning an array**

You may wish to inject different implementations into each class or inject any primitive values by using a callable returning the resolve values. The first argument of the callable will always be the resolved object, but you can typehint any other object you may need next.

```
use Tobento\Service\ResolverContainer\ResolverFactory;

interface UserInterface {}
class GuestUser implements UserInterface {}
class AdminUser implements UserInterface {}

class ServiceFoo {
    public function __construct(
        protected UserInterface $user
    ) {}
}

class ServiceBar {
    public function __construct(
        protected UserInterface $user
    ) {}
}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(UserInterface::class, GuestUser::class);

$resolver->on(ServiceFoo::class, function($service, AdminUser $user) {
    return ['user' => $user];
});

var_dump($resolver->get(ServiceFoo::class));
// object(ServiceFoo)#12 (1) { ["user":protected]=> object(AdminUser)#17 (0) { } }

var_dump($resolver->get(ServiceBar::class));
// object(ServiceBar)#11 (1) { ["user":protected]=> object(GuestUser)#14 (0) { } }
```

#### Call Methods

[](#call-methods)

You may want to call methods after an object is resolved:

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class FooService {}
class AdminUser {
    protected array $called = [];

    public function set(FooService $service, string $value)
    {
        $this->called[] = [$service, $value];
    }

    public function getCalled(): array
    {
        return $this->called;
    }
}

$resolver = new ResolverFactory()->createResolver();

$resolver->on(AdminUser::class)
         ->callMethod('set', ['value' => 'foo']);

$user = $resolver->get(AdminUser::class);

var_dump($user->getCalled());
// array(1) { [0]=> array(2) { [0]=> object(FooService)#15 (0) { } [1]=> string(3) "foo" } }
```

**Declare as trait**

You may calling methods when a class uses a trait:

```
use Tobento\Service\ResolverContainer\ResolverFactory;

trait SomeMethods {
    protected array $called = [];

    public function set(string $value)
    {
        $this->called[] = $value;
    }

    public function getCalled(): array
    {
        return $this->called;
    }
}

class AdminUser {
    use SomeMethods;
}

$resolver = new ResolverFactory()->createResolver();

$resolver->on(SomeMethods::class)
         ->trait()
         ->once(false)
         ->callMethod('set', ['value' => 'foo']);

$user = $resolver->get(AdminUser::class);

var_dump($user->getCalled());
// array(1) { [0]=> string(3) "foo" }
```

#### Using Once

[](#using-once)

The **on** method is handled once as default. You may use the **once** method as to be always handled:

```
class AdminUser {}
class GuestUser {}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(AdminUser::class)->prototype();

$resolver->on(AdminUser::class, GuestUser::class);
         ->once(false);

var_dump($resolver->get(AdminUser::class));
// object(GuestUser)#10 (0) { }

var_dump($resolver->get(AdminUser::class));
// object(GuestUser)#10 (0) { }
```

#### Using Prototype

[](#using-prototype)

You may using the **prototype** method returning always a new instance:

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class AdminUser {}
class GuestUser {}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(AdminUser::class)->prototype();

$resolver->on(AdminUser::class, GuestUser::class)
         ->once(false)
         ->prototype();

var_dump(
    $resolver->get(AdminUser::class)
    === $resolver->get(AdminUser::class)
);
// bool(false)
```

#### Using Instanceof

[](#using-instanceof)

You may modify or replace objects when the object belongs to a specific class by using the **instanceof** method:

```
use Tobento\Service\ResolverContainer\ResolverFactory;

interface UserInterface {}
class User implements UserInterface {}
class GuestUser extends User {}
class AdminUser extends User {}

$resolver = new ResolverFactory()->createResolver();

$resolver->set(UserInterface::class, GuestUser::class);

$resolver->on(User::class, function($user) {
    return new AdminUser();
})->instanceof();

var_dump($resolver->get(UserInterface::class));
// object(AdminUser)#12 (0) { }
```

#### Using Priority

[](#using-priority)

You may use the **priority** method to handle the execution order. The default priority is 1000, highest gets handled first:

```
use Tobento\Service\ResolverContainer\ResolverFactory;

class AdminUser {}
class GuestUser {}
class EditorUser {}

$resolver = new ResolverFactory()->createResolver();

$resolver->on(AdminUser::class, EditorUser::class)
         ->priority(500);

$resolver->on(AdminUser::class, GuestUser::class)
         ->priority(1000);

var_dump($resolver->get(AdminUser::class));
// object(EditorUser)#8 (0) { }
```

### Rule

[](#rule)

You may add a rule by using the **rule** method:

```
use Tobento\Service\ResolverContainer\ResolverFactory;
use Tobento\Service\Resolver\RuleInterface;
use Tobento\Service\Resolver\OnRule;

class AdminUser {}
class GuestUser {}

$resolver = new ResolverFactory()->createResolver();

$rule = new OnRule(AdminUser::class, GuestUser::class);

var_dump($rule instanceof RuleInterface);
// bool(true)

$resolver->rule($rule);

$user = $resolver->get(AdminUser::class);

var_dump($user);
// object(GuestUser)#9 (0) { }
```

### Container

[](#container)

```
use Tobento\Service\ResolverContainer\ResolverFactory;
use Psr\Container\ContainerInterface;

$resolver = new ResolverFactory()->createResolver();

var_dump($resolver->container() instanceof ContainerInterface);
// bool(true)
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance63

Regular maintenance activity

Popularity15

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity70

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

Recently: every ~168 days

Total

6

Last Release

224d ago

Major Versions

1.x-dev → 2.02025-09-30

PHP version history (2 changes)1.0.0PHP &gt;=8.0

2.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (10 commits)")

---

Tags

phpcontainerPSR-11Autowiringpackageresolvertobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-service-resolver/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-service-resolver/health.svg)](https://phpackages.com/packages/tobento-service-resolver)
```

###  Alternatives

[devanych/di-container

Simple implementation of a PSR-11 dependency injection container

124.2k3](/packages/devanych-di-container)[gacela-project/container

A minimalistic container dependency resolver

1175.2k2](/packages/gacela-project-container)

PHPackages © 2026

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