PHPackages                             phossa2/di - 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. phossa2/di

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

phossa2/di
==========

A powerful Container-Interop/PSR-11 implementation of dependency injection library for PHP.

2.0.1(9y ago)321MITPHPPHP &gt;=5.4.0

Since Jul 18Pushed 6y ago1 watchersCompare

[ Source](https://github.com/phossa2/di)[ Packagist](https://packagist.org/packages/phossa2/di)[ Docs](https://github.com/phossa2/di)[ RSS](/packages/phossa2-di/feed)WikiDiscussions master Synced 4w ago

READMEChangelog (2)Dependencies (4)Versions (3)Used By (0)

phossa2/di \[ABANDONED\]
========================

[](#phossa2di-abandoned)

**PLEASE USE [phoole/di](https://github.com/phoole/di) library instead**

[![Build Status](https://camo.githubusercontent.com/97da3f78081d74941e0dddd64065d0e12830189921f85f170103c002a057b661/68747470733a2f2f7472617669732d63692e6f72672f70686f737361322f64692e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/phossa2/di)[![Code Quality](https://camo.githubusercontent.com/30535a8bc44b780e887849856aad139c36201facb9d6979932eddc2ea53da06d/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f70686f737361322f64692f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/phossa2/di/)[![Code Climate](https://camo.githubusercontent.com/62bd4fb05b4cbb1911146e9962a7925da9a9860f30719c3ff7fe4d6229efb9d3/68747470733a2f2f636f6465636c696d6174652e636f6d2f6769746875622f70686f737361322f64692f6261646765732f6770612e737667)](https://codeclimate.com/github/phossa2/di)[![PHP 7 ready](https://camo.githubusercontent.com/0adee8a0d8969ad74d018663110b36424b182eb5cb08e7d9b746d2fb94545d72/687474703a2f2f7068703772656164792e74696d6573706c696e7465722e63682f70686f737361322f64692f6d61737465722f62616467652e737667)](https://travis-ci.org/phossa2/di)[![HHVM](https://camo.githubusercontent.com/8ed0ee748295e88beb43fe9272facb8b1217f547fd8ec0762c22054883bd685a/68747470733a2f2f696d672e736869656c64732e696f2f6868766d2f70686f737361322f64692e7376673f7374796c653d666c6174)](http://hhvm.h4cc.de/package/phossa2/di)[![Latest Stable Version](https://camo.githubusercontent.com/d5bc9e4df1738c291030982899c9211c604fb7df12462b5b418f02f5cdd101fd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f767072652f70686f737361322f64692e7376673f7374796c653d666c6174)](https://packagist.org/packages/phossa2/di)[![License](https://camo.githubusercontent.com/4fc6538ded72843e26a272d300ce4c95da083ce92576e10e4fdd505d579a8125/68747470733a2f2f696d672e736869656c64732e696f2f3a6c6963656e73652d6d69742d626c75652e737667)](http://mit-license.org/)

**phossa2/di** is a *fast* and *powerful* [Container-Interop](https://github.com/container-interop/container-interop "Container-Interop") or [PSR-11](https://github.com/container-interop/fig-standards/blob/master/proposed/container.md "Container interface") implementation of dependency injection library for PHP. It builds upon the versatile [phossa2/config](https://github.com/phossa2/config "phossa2/config") library and supports [autowiring](#auto), [container delegation](#delegate), [object decorating](#decorate), [object scope](#scope) and more.

It requires PHP 5.4, supports PHP 7.0+ and HHVM. It is compliant with [PSR-1](http://www.php-fig.org/psr/psr-1/ "PSR-1: Basic Coding Standard"), [PSR-2](http://www.php-fig.org/psr/psr-2/ "PSR-2: Coding Style Guide"), [PSR-4](http://www.php-fig.org/psr/psr-4/ "PSR-4: Autoloader"), and proposed [PSR-5](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md "PSR-5: PHPDoc"), [PSR-11](https://github.com/container-interop/fig-standards/blob/master/proposed/container.md "Container interface").

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

[](#installation)

Install via the `composer` utility.

```
composer require "phossa2/di=2.*"

```

or add the following lines to your `composer.json`

```
{
    "require": {
       "phossa2/di": "2.*"
    }
}
```

Usage
-----

[](#usage)

- With [*autowiring*](#auto) of classes.

    A couple of simple classes as follows,

    ```
    // file cache.php
    class MyCache
    {
        private $driver;

        public function __construct(MyCacheDriver $driver)
        {
            $this->driver = $driver;
        }

        // ...
    }

    class MyCacheDriver
    {
        // ...
    }
    ```

    Instead of creating `MyCacheDriver` and `MyCache` instances manually, you may get the both instances automatically using the DI container,

    ```
    use Phossa2\Di\Container;

    // should be aware of these classes
    require_once __DIR__ . '/cache.php';

    // create the container
    $container = new Container();

     // 'MyCache' classname as the service id
    if ($container->has('MyCache')) {
        $cache = $container->get('MyCache');
    }
    ```

    With [autowiring](#auto) is turned on by default, the container will look for the `MyCache` class if no service defined as 'MyCache', and resolves its dependency injection (here, is the `MyCacheDriver` instance) automatically when creating the `MyCache` instance.
- With manual service addition using `set()`

    Services can be added to the container manually by using `set()` method.

    ```
    use Phossa2\Di\Container;

    // should be aware of these classes
    require_once __DIR__ . '/cache.php';

    // create the container
    $container = new Container();

    // turn off autowiring
    $container->auto(false);

    // define service with an array
    $container->set('cache', [
        'class' => 'MyCache', // classname
        'args'  => ['${#driver}'] // constructor arguments
    ]);

    // add service 'driver' with a callback
    $container->set('driver', function() {
        return new \MyCacheDriver();
    });

    // get the service
    var_dump($container->get('cache') instanceof \MyCache); // true
    ```

    A [service reference](#sref) `'${#driver}'` used in the constructor arguments here indicating it is the `driver` service instance from the container.
- With configuration from files or array

    Container uses a `Phossa2\Config\Interfaces\ConfigInterface` instance as its definition resolver for parameter and service definitions. The config instance may either read configs from files or get configs from an array as follows,

    ```
    use Phossa2\Di\Container;
    use Phossa2\Config\Config;

    $configData = [
        // container service definitions
        'di.service' => [
            // cache service
            'cache'  => ['class' => 'MyCache', 'args' => ['${#driver}']],

            // cache driver, classname directly
            'driver' => 'MyCacheDriver',
        ],

        // common methods to run after each instantiation
        'di.common' => [
            [
              function($obj) { return $obj instanceof \MyCacheDriver; }, // tester
              function($obj, $container) { echo "ok"; } // runner
            ],
        ],

        // init methods after container created
        'di.init' => [
              // default section
              'default' => [
                  ['setLogger', ['${#logger}']],
                  // ...
              ],

              // my own section
              'mystuff' => [
              ],
        ],
    ];

    // create $config instance with provided data
    $config = new Config(null, null, $configData);

    // instantiate container with $config instance and definition base node 'di'
    $container = new Container($config, 'di');

    // get service by id 'cache' (di.service.cache)
    $cache = $container->get('cache');

    // true
    var_dump($cache instanceof \MyCache);
    ```

    By default, container related configurations are under the node `di` and service definitions are under the `di.service` node.

Features
--------

[](#features)

- **References**

    References in the form of '${reference}' can be used to refer to predefined parameters from the config or services in the container.

    **Characters of `'$', '{', '}', '.'` are not allowed in reference name**. Characters of `'#', '@'` have special meanings, such that should not be part of *normal* service names.

    - Parameter references

        See [phossa2/config reference](https://github.com/phossa2/config#ref) for detail. Parameter references are read from configuration files or can be defined by container method `param()` as follows,

        ```
        // define a new parameter for the container
        $container->param('cache.dir', '${system.tmpdir}/cache');

        // use the cache.dir parameter defined above
        $container->set('cache', [
            'class' => '${cache.class}', // predefined in file
            'args'  => ['${cache.dir}']  // just defined above
        ]);
        ```
    - Service references

        Service reference in the form of '${#service\_id}' can be used to referring a service instance in the container (or in the [delegator](#delegate)).

        ```
        $container->set('cache', [
            'class' => '${cache.class}',
            'args'  => ['${#cache_driver}'] // service reference
        ]);
        ```

        **Two reserved service references are '${#container}' and '${#config}'**. These two are refering the container instance itself and the config instance it is using. These two can be used just like other service references.
    - Using references

        References can be used anywhere in the configs or as the arguments for all container methods (except for the paramter `$id` of the methods).

        ```
        // run(callable, arguments) with references
        $container->run(['${#logger}', 'warning'], ['warning from ${log.facility}']);

        // resolve references
        $data = ['${system.dir}', '${#logger}'];
        $container->resolve($data); // all references in $data are now resolved
        ```
- **Autowiring and mapping**

    *Autowiring* is the ability of container instantiating objects and resolving its dependencies automatically by their classname. The base for autowiring is the PHP function parameter *type-hinting*.

    By reflecting on class, constructor and methods, *phossa2/di* is able to find the right class for the instance (user need to use the classname as the service id) and right classes for its dependencies (type-hinted with the classnames).

    If interface name is used for dependency type-hint, users may set up the mapping of interfaces to the right classnames as follows,

    ```
    // map an interface to a classname
    $container->set(
        'Phossa2\\Cache\\CachePoolInterface', // MUST NO leading backslash
        'Phossa2\\Cache\\CachePool'
    );

    // map an interface to a service id reference
    $container->set('Phossa2\\Cache\\CachePoolInterface', '${#cache}');

    // map an interface to a parameter reference
    $container->set('Phossa2\\Cache\\CachePoolInterface', '${cache.class}');

    // map an interface to a callback
    $container->set('Phossa2\\Cache\\CachePoolInterface', function() {
        return new \Phossa2\Cache\CachePool();
    });
    ```

    Or define mappings in the config node `di.service` as follows,

    ```
    $configData = [
        // ...
        'di.service' => [
            'Phossa2\\Cache\\CachePoolInterface' => '${cache.class}',
            // ...
        ],
        // ...
    ];
    ```

    Autowiring can be turned on/off. Turning off autowiring will enable user to check any defintion errors without automatic loading.

    ```
    // turn off auto wiring
    $container->auto(false);

    // turn on auto wiring
    $container->auto(true);
    ```
- **Object decorating**

    *Object decorating* is to apply decorating changes (executing methods etc.) right after the instantiation of a service instance.

    - Decorating methods for *individual instance* only

        ```
        $container->set('cache', [
            'class'   => 'Phossa2\\Cache\\Cache',
            'args'    => ['${#cachedriver}'], // constructor arguments
            'methods' => [
                ['clearCache'], // method of $cache
                ['setLogger', ['${#logger}']], // method with arguments
                [[$logger, 'setLabel'], ['cache_label']], // callable with arguments
                [['${#driver}, 'init']], // pseduo callable
                // ...
            ],
        ]);
        ```

        By adding `methods` section into the `cache` service definition in the form of `[ callableOrMethodName, OptionalArgumentArray ]`, these methods will be executed right after `cache` instantiation.

        `callableOrMethodName` here can be,

        - method name of current instance
        - a valid callable
        - a psedudo callable with references (after resolving the references, it is a valid callable).

        `OptionalArgumentArray` here can be,

        - empty
        - array of values or references
    - Common decorating methods for *all instances*

        ```
        $configData = [
            // common methods for all instances
            'di.common' => [
                // [ tester(): bool, method ]
                [
                    function($object, $container) {
                        return $object instanceof 'Psr\\Log\\LoggerAwareInterface'
                    },
                    ['setLogger', ['${#logger}']]
                ],
                // ...
            ],
        ];
        ```

        Common methods can be configured in the 'di.common' node to apply to all the instances right after their instantiation. The definition consists of two parts, the first is a tester callable takes current instance and the container as parameters and returns a boolean value. The second part is in the same method format as in the service definition 'methods'.

        To skip execution of common methods for one service, define it with `skip`as follows,

        ```
        $container->set('logger', [
            'class' => 'Phossa2\Logger\Logger',
            'skip'  => true
        ]);
        ```
- **Container delegation**

    According to [Interop Container Delegate Lookup](https://github.com/container-interop/fig-standards/blob/master/proposed/container.md), container may register a delegate container (the delegator), and

    - Calls to the `get()` method should only return an entry if the entry is part of the container. If the entry is not part of the container, an exception should be thrown (as requested by the `ContainerInterface`).
    - Calls to the `has()` method should only return true if the entry is part of the container. If the entry is not part of the container, false should be returned.
    - If the fetched entry has dependencies, **instead** of performing the dependency lookup in the container, the lookup is performed on the delegate container (delegator).
    - **Important** By default, the lookup *SHOULD* be performed on the delegate container only, not on the container itself.

    *phossa2/di* fully supports the delegate feature.

    ```
    use Phossa2\Di\Delegator;

    // create delegator
    $delegator = new Delegator();

    // create container
    $container = new Container();

    // insert container into delegator
    $delegator->addContainer($container);

    // get from delegator now
    $cache = $delegator->get('cache');
    ```
- **Object scope**

    - Shared or single scope

        By default, service instances in the container are shared inside the container. Actually they have the scope of `Container::SCOPE_SHARED`. If users want different instance each time, they may either use the method `one()` or define the service with `Container::SCOPE_SINGLE` scope.

        ```
        // cache service by default is in shared scope
        $cache1 = $container->get('cache');

        // get again
        $cache2 = $container->get('cache');

        // same
        var_dump($cache1 === $cache2); // true

        // a new cache instance with 'one()'
        $cache3 = $container->one('cache');

        // different instances
        var_dump($cache1 !== $cache3); // true

        // but both share the same cacheDriver dependent service
        var_dump($cache1->getDriver() === $cache3->getDriver()); // true
        ```

        Or define the service as `Container::SCOPE_SINGLE`

        ```
        $container->set('cache', [
            'class' => '\\Phossa2\\Cache\\CachePool'),
            'scope' => Container::SCOPE_SINGLE
        ]);

        // each get() will return a new cache
        $cache1 = $container->get('cache');
        $cache2 = $container->get('cache');

        // different instances
        var_dump($cache1 !== $cache2); // true

        // dependent service are shared
        var_dump($cache1->getDriver() === $cache->getDriver()); // true
        ```

        Set the container's default scope to `Container::SCOPE_SINGLE` will cause each `get()` returns a new instance (unless 'scope' is explicitly defined as for this service).

        ```
        // set default scope to SCOPE_SINGLE
        $container->share(false);

        // a new copy of cache service
        $cache1 = $container->get('cache');

        // another new cache service
        $cache2 = $container->get('cache');

        // different instances
        var_dump($cache1 !== $cache2); // true

        // dependencies are different
        var_dump($cache1->getDriver() !== $cache->getDriver()); // true
        ```
    - Use your own scope

        You may get an instance in your own scope as follows, no matter whatever the default scope or the defined scope for this instance,

        ```
        // instance in scope 'myScope'
        $cacheOfMyScope = $container->get('cache@myScope');

        // new instance in single scope, even though you specified one
        $cacheOfSingle = $container->one('cache@myScope');

        // instance in shared scope
        $cache = $container->get('cache');
        ```

        Service references can also have scope defined as follows,

        ```
        $container->set('cache', [
            'class' => 'Phossa2\\Cache\\Cache',
            'args'  => ['${#driver@myScope}'] // use driver of myScope
        ]);
        ```
    - Share instance only in certain object

        Sometimes, user may want to share one instance only inside certain object.

        ```
        class A {
            private $b, $c;

            public function __construct(B $b, C $c) {
                $this->b = $b;
                $this->c = $c;
            }

            public function getB() {
                return $this->b;
            }

            public function getC() {
                return $this->c;
            }
        }

        class B {
            private $c;
            public function __construct(C $c) {
                $this->c = $c;
            }
        }

        class C {
        }

        // an instance of A
        $a1 = $container->one('A');

        // another instance of A
        $a2 = $container->one('A');

        // $a1 and $a2 is different
        var_dump($a1 !== $a2); // true

        // C is the same under A
        var_dump($a1->getC() === $a1->getB()->getC()); // true

        // C is also shared among different A
        var_dump($a1->getC() === $a2->getC()); // true
        ```

        In previous code, `C` is not only shared under the `A`, but also shared among different instances of `A`. What if user want to share `C` only under the `A` but not between `A` ?

        By setting scope of `C` to '#A' as follows,

        ```
        // this scope only takes effect when under service A
        $container->set('C', [ 'class' => 'C', 'scope' => '#A']);

        // an instance of A
        $a1 = $container->one('A');

        // another instance of A
        $a2 = $container->one('A');

        // C is different among different A
        var_dump($a1->getC() !== $a2->getC()); // true

        // C is same under one A
        var_dump($a1->getC() === $a1->getB()->getC()); // true
        ```
- **Array access and read only**

    Both `Phossa2\Di\Container` and `Phossa2\Di\Delegator` implements `\ArrayAccess` interface.

    ```
    $container = new Container();
    $delegator = new Delegator();

    $delegator->addContainer($container);

    // equals to $delegator->has('A')
    if (isset($delegator['A'])) {
        var_dump($delegator['A'] === $container['A']); // true
    }
    ```

    By default `Phossa2\Di\Container` is writable which means user can add new service definitions to the container manually by using `set()`.

    **Note** If container is set readonly, [auto wiring](#auto) is turned off automatically.

    To get a readonly container,

    ```
    $container = new Container();
    $container->setWritable(false);

    var_dump($container->isWritable() === false); // true

    // delegator also
    $delegator = new Delegator();
    $delegator->setWritable(false);

    var_dump($delegator->isWritable() === false); // true
    ```

APIs
----

[](#apis)

- Container related

    - `get(string $id): object` from *ContainerInterface*

        If not found, `Phossa2\Di\Exception\NotFoundException` is thrown. `$id`may have '@scope' appended. An array can be used as the second parameter for object constructor's arguments.
    - `has(string $id): bool` from *ContainerInterface*

        `$id` may have '@scope' appended.
    - `one(string $id, array $args = []): object` from *ExtendedContainerInterface*

        Get a new instance for this `$id`. May provide new arguments for the object constructor.
    - `run(mixed $callable, array $args = []): mixed` from *ExtendedContainerInterface*

        Execute a callable or pseduo callable (with references) with provided arguments (may contain references also)
    - `param(string $name, mixed $value): bool` from *ExtendedContainerInterface*

        Set a parameter in the container's config tree for later to be used as a reference. Returns a bool value to indicate status.
    - `alias(string $id, object|string $object): bool` from *ExtendedContainerInterface*

        Aliasing an object as `$id` in the container. Difference with `set()` method is that getting this object will skip the execution of common methods.

        Returns `true` on success and `false` on failure.
    - `auto(bool $flag): $this` from *AutoWiringInterface*

        Set container autowiring `ON` or `OFF`.
    - `isAuto(): bool` from *AutoWiringInterface*

        Test container is auto wiring `ON` or `OFF`.
    - `resolve(mixed &$data): $this` from *ReferenceResolveInterface*

        Recursively resolving references in the `$data`. `$data` might be `string`or `array`. Other data type will be untouched.
    - `share(bool $flag = true): $this` from *ScopeInterface*

        Make container default scope to `Container::SCOPE_SHARED` or `Container::SCOPE_SINGLE`.
    - `set(string $id, mixed $value): bool` from *WritableInterface*

        Set a service with `$id` into the container. `$value` can be an array in the form of array as follows,

        ```
        $value = [
            'class' => mixed,   // classname/object/callback etc.
            'args'  => array,   // arguments for the constructor or callback
            'scope' => string,  // default scope for this service
            'skip'  => bool,    // skip common methods for the instance
        ];
        ```

        or `$value` can be classname, object, callback etc. Returns `true` on success or `false` on failure. Container has to be writable, otherwise a `LogicException` will be thrown.
    - `isWritable(): bool` from *WritableInterface*

        Is this container writable ?
    - `setWritable(bool $writable): bool` from *WritableInterface*

        Set this container writable or readonly.
- Delegator related

    - `get(string $id): object` from *ContainerInterface*

        Get service from the delegator. If not found, `Phossa2\Di\Exception\NotFoundException` is thrown. `$id` may have '@scope' appended as long as underlying container supports this feature.
    - `has(string $id): bool` from *ContainerInterface*

        `$id` may have '@scope' appended as long as underlying container supports this feature.
    - `set(string $id, mixed $value): bool` from *WritableInterface*

        Set a service with `$id` into the delegator as long as the delegator is writable.
    - `isWritable(): bool` from *WritableInterface*

        Is this delegator writable ?
    - `setWritable(bool $writable): bool` from *WritableInterface*

        Set this delegator writable or readonly.
    - `addContainer(ContainerInterface $container): $this` from *DelegatorInterface*

        Add a container to the delegator.

Change log
----------

[](#change-log)

Please see [CHANGELOG](CHANGELOG.md) from more information.

Testing
-------

[](#testing)

```
$ composer test
```

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

[](#contributing)

Please see [CONTRIBUTE](CONTRIBUTE.md) for more information.

Dependencies
------------

[](#dependencies)

- PHP &gt;= 5.4.0
- phossa2/config &gt;= 2.0.12
- phossa2/shared &gt;= 2.0.21

License
-------

[](#license)

[MIT License](http://mit-license.org/)

###  Health Score

27

—

LowBetter than 47% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 96.8% 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 ~2 days

Total

2

Last Release

3634d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/19922046?v=4)[Hong Zhang](/maintainers/phossa2)[@phossa2](https://github.com/phossa2)

---

Top Contributors

[![phossa](https://avatars.githubusercontent.com/u/8499165?v=4)](https://github.com/phossa "phossa (61 commits)")[![phossa2](https://avatars.githubusercontent.com/u/19922046?v=4)](https://github.com/phossa2 "phossa2 (2 commits)")

---

Tags

containercontainer-interopdependency-injectionphossa2

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/phossa2-di/health.svg)

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

###  Alternatives

[psr/container

Common Container Interface (PHP FIG PSR-11)

10.0k1.1B4.6k](/packages/psr-container)[php-di/php-di

The dependency injection container for humans

2.9k55.5M1.2k](/packages/php-di-php-di)[pimple/pimple

Pimple, a simple Dependency Injection Container

2.7k134.5M1.4k](/packages/pimple-pimple)

PHPackages © 2026

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