PHPackages                             jakewhiteley/hodl - 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. jakewhiteley/hodl

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

jakewhiteley/hodl
=================

A lightweight PSR-11 dependency injection container for PHP, which sites in between Pimple and the Laravel Container

1.7.0(3y ago)55.6k↑500%1[1 PRs](https://github.com/jakewhiteley/hodl/pulls)1MITPHPPHP &gt;=7.4.0

Since Apr 28Pushed 1y ago3 watchersCompare

[ Source](https://github.com/jakewhiteley/hodl)[ Packagist](https://packagist.org/packages/jakewhiteley/hodl)[ RSS](/packages/jakewhiteley-hodl/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (10)Dependencies (4)Versions (20)Used By (1)

Hodl DI
=======

[](#hodl-di)

[![Travis](https://camo.githubusercontent.com/44dcfa6fbc1619eb89aa4e5c637315b6756860ed06cb7aa61f9ddd1e80de3424/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f6a616b6577686974656c65792f686f646c2e7376673f7374796c653d666f722d7468652d6261646765)](https://travis-ci.org/jakewhiteley/hodl) [![PHP from Packagist](https://camo.githubusercontent.com/31157660897b8f9f53cb1c230a1b175493b84a6d489fd76c1937759503476cb0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6a616b6577686974656c65792f686f646c2e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/jakewhiteley/hodl)

Hodl provides full autowiring capabilities for Inversion of Control, but is simple enough to use as a standalone service container without any faff.

It's a simple `ArrayAccess` Service container which takes inspiration from both Laravel and Pimple (Symfony), but sits comfortably in the middle.

Basic Usage
-----------

[](#basic-usage)

A service can be added to the container by providing the class name, and a definition for the service.

```
$hodl->add('Some\Namespace\Foo', function() {
	return new Foo();
});
```

You should always register a service using it's full class name. This is so that the autowiring can work and classes can have their dependencies injected with no fuss.

### Retrieving a service

[](#retrieving-a-service)

As simple as it gets:

```
$foo = $hodl->get('Some\Namespace\Foo');
```

### Checking if a service exists

[](#checking-if-a-service-exists)

As all services are referenced by the key you defined it with, you can use `has()` to check if that key has been defined previously:

```
use Namespace\Foo;

// using the ::class shorthand
$hodl->add(Foo::class, function() {
    return new Foo();
});

$hodl->has(Foo::class); // true
$hodl->has('some\other\class'); // false
```

### Removing services

[](#removing-services)

As the Container implements ArrayAccess you can use `unset()` or the `remove()` method to remove a class:

```
$hodl['foo'] = function(){
    return new Foo();
};

$hodl->has('foo'); // true

$hodl->remove('foo');

$hodl->has('foo'); // false
```

Removing a service will also remove any aliases or bound interfaces as well (more on that below).

### ArrayAccess style

[](#arrayaccess-style)

As Hodl implements `ArrayAccess`, you can achieve the above like this instead:

```
// add
$hodl['Some\Namespace\Foo'] = function(){
    return new Foo();
};

// get
$foo = $hodl['Some\Namespace\Foo'];

// check
if (isset($hodl['Some\Namespace\Foo')) // ...

// remove
unset($hodl['Some\Namespace\Foo']);
```

### Service definitions

[](#service-definitions)

When adding a new service definition, the `callable` which returns the class is passed an instance of `Hodl`, which can be used for passing arguments derived from services already within the container. **Note** You should not pass services directly into the constructor of your service. For that we have the magic of [autowiring](#autowiring-resolving-dependencies).

```
$hodl->get('Baz', function($hodl) {
	return new Baz($hodl->get('Some\Namespace\Foo')->someProp);
});
```

Singletons
----------

[](#singletons)

The above examplse will return a new instance of the service no matter when it is fetched. You can also specify that the same instance should be returned each time by using the `addFactory()` method:

```
$hodl->addSingleton(Bar::class, function() {
	return new Bar();
});
```

Instances
---------

[](#instances)

You can also add a specific instance as a service. As this is already booted, `Hodl` can derrive the class name pretty easily so there is no need to supply that.

```
$instance = new Foo\Bar();
$instance->prop = 'foobar';

$hodl->addInstance($instance);

// ...

$hodl->get('Foo\Bar')->prop // equals 'foobar'
```

Aliases
-------

[](#aliases)

Sometimes it is tiresome typing in fully qualified class names to get access to a service. Luckily you can also define an **alias** to a service for quick retrieval:

```
// using the ::class shorthand
$hodl->add(Foo::class, function() {
    return new Foo();
});

// Adda alias.
$hodl->alias(Foo:class, 'myAlias');

$hodl->has(Foo::class); // true
$hodl->has('myAlias'); // true
```

#### Removing aliases

[](#removing-aliases)

If at somepoint you need to remove an alias, or binding (see below) then you can use the `removeAlias($alias)` method.

Autowiring (resolving dependencies)
-----------------------------------

[](#autowiring-resolving-dependencies)

Aside as using it as a container for passing objects around, it can also be used to auotmatically resolve objects using the Reflection API and achieve Inversion of Control.

Consider the following object:

```
namespace Foo;

class Foo
{
    function __construct( Bar $bar )
    {
       	$this->bar = $bar;
    }
}
```

When this object is created, it needs to be passed an instance of `Foo\Bar` as the first argument.

Using the `resolve()` method this is super easy:

```
$foo = $hodl->resolve('Foo\Foo');
```

The object will be created an an instance of `Foo\Bar` will be initialized and passed through automatically.

This works recursively so any dependencies of `Foo\Bar` will be magically resolved as well.

### Passing arguments

[](#passing-arguments)

The resolve method also accepts a second argument, which is an array of extra parameters you want to pass to the object constructors.

The keys of this array must be the variable name of the parameter.

```
// using the Foo class in the previous example, but with a following constructor:
// function __construct( Bar $bar, int $someInt, string $someString = 'string' ) { ...

// by not passing someString as a key, the default of 'string' will be used
$foo = $hodl->resolve('Foo\Foo', [
	'someInt' => 42
]);
```

### Resolving using services

[](#resolving-using-services)

The above examples have an empty container, so all services are injected as new generic instances of that class. But if a service exists within the container, that service will be used instead - allowing your specific instance or a persistent object to be passed to any object which needs it.

```
class Foo
{
	public $var = 'foo';
}

class Bar
{
	public $foo;

	public function __construct(Foo $foo)
	{
		$this->foo = $foo;
	}
}

// Add Foo as a singleton
$hodl->addSingleton('Foo', function() {
	return new Foo();
});

$hodl['Foo']->var = 'changed!';

$var = $hodl->resolve('Bar')->foo->var; // equals 'changed!'
```

Don't be afraid to use `resolve()` when adding a service definition to the container either!

```
$hodl->add('Bar', function($hodl) {
	return $hodl->resolve('Bar'); // All of Bar's dependencies will be injected as soon as it is fetched
});
```

### Binding implementations to interfaces

[](#binding-implementations-to-interfaces)

A really useful feature when using the autowiring functionality is to be able to specify in a constructor an interface, and have Hodl deal with passing the correct implementation to the resolved class.

Consider the following:

```
// Basic interface
interface HelloWorld
{
	public function output();
}

// Service
class NeedsResolving
{
	public function __construct(HelloWorld $writer)
	{
		$this->writer = $writer;
	}

	public function output()
	{
		$this->writer->output();
	}
}
```

We know the `NeedsResolving` class needs some kind of `HelloWorld` implementation to actually work. We can let Hodl know which one using the `bind()` method:

```
class MyPrinter implements HelloWorld
{
	public function output()
	{
		echo 'Hello world!';
	}
}

$hodl->bind(MyPrinter::class, HellowWorld::class);

// Correctly gets an instance of MyPrinter
$foo = $hodl->resolve(NeedsResolving::class);

$foo->output(); // Outputs 'Hello world!'
```

#### Removing bindings

[](#removing-bindings)

As under the hood `bind()` as an alias for `alias()`, the `removeAlias($interface)` method will remove a binding. Useful if for whatever reason you had to hot-swap an implementation out for another.

Resolving methods
-----------------

[](#resolving-methods)

The `resolveMethod($class, $methodName, $args)` method allows autowiring of class members the same way that `resolve()` works on classes.

```
$hodl->resolveMethod(Foo::class, 'someMethod');
```

`resolveMethod` will call the supplied method, recursively inject dependencies and allow you to pass extra non-object parameters as per the `resolve` examples above. This works on static methods as well as public ones.

### Resolving instance methods

[](#resolving-instance-methods)

The example above shows `someMethod` being execcuted and returned on a new instance of `Foo`, but you can also pass a specific instance instead of the class name:

```
$foo = new Foo();
$return = $hodl->resolveMethod($foo, 'someMethod', ['amount_of_awesome' => 100]);
```

Both `resolve` and `resolveMethod` could therefore be used together to create a new fully resolved object and execute a method.

```
class Bar
{
	public $foo;

	public function __construct(Foo $foo)
	{
		$this->foo = $foo;
	}

	public function methodName(Foo\Baz $baz)
	{
		return $this->foo->var * $baz->var;
	}
}

// Fully resolves methodName and returns an instance of Foo\Baz
$resolvedBaz = $hodl->resolveMethod(
	$hodl->resolve('Bar'),
	'methodName'
);
```

Conclusion
----------

[](#conclusion)

By adding services to Hodl, your code can achieve complete inversion of control and manage classes application-wide with no need for a single `new` keyword or singleton in sight.

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

[](#contributing)

If you have any improvements, bugs, or feature requests; feel free to open up an issue or PR.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance30

Infrequent updates — may be unmaintained

Popularity25

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 88.5% 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 ~119 days

Recently: every ~148 days

Total

16

Last Release

1138d ago

PHP version history (4 changes)1.0.0PHP &gt;=7.0

1.5.0PHP &gt;=7.4

1.5.1PHP &gt;=7.2.0

1.6.0PHP &gt;=7.4.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/e0b577f462814ec2d065484507f993625cb36a605b2b97831128adf31c83c1be?d=identicon)[JakeWhiteley](/maintainers/JakeWhiteley)

---

Top Contributors

[![jakewhiteley](https://avatars.githubusercontent.com/u/3481634?v=4)](https://github.com/jakewhiteley "jakewhiteley (54 commits)")[![jakewhiteley-gc](https://avatars.githubusercontent.com/u/39829475?v=4)](https://github.com/jakewhiteley-gc "jakewhiteley-gc (7 commits)")

---

Tags

arrayaccessdependency-injectioninversionphp7resolvingservice-managerphpcontainerdiservicesinversion of controlautomatically resolve

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/jakewhiteley-hodl/health.svg)

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

###  Alternatives

[league/container

A fast and intuitive dependency injection container.

86387.8M342](/packages/league-container)[capsule/di

A PSR-11 compliant autowiring dependency injection container.

2857.5k2](/packages/capsule-di)[devanych/di-container

Simple implementation of a PSR-11 dependency injection container

124.2k3](/packages/devanych-di-container)

PHPackages © 2026

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