Config: Container PSR-11 and Dependency Injection

Build Status Opensource ByJG GitHub source GitHub license GitHub release Scrutinizer Code Quality

A very basic and minimalist PSR-11 implementation for config management and dependency injection.

How it Works?

The container is created based on the configuration you created (dev, homolog, test, live, …) defined in array and .env files;

See below how to setup:

Setup files

Create in your project root at the same level of the vendor directory a folder called config.

Inside these folders create files called "config-dev.php", "config-test.php" where dev, test, live, etc are your configuration sets.

Your folder will look like to:

<project root>
    +-- config
           + .env
           + config-dev.php
           + config-dev.env
           + config-homolog.php
           + config-homolog.env
           + config-test.php
           + config-live.php
   +-- vendor
   +-- composer.json

Select the configuration you will use

Read from the environment variable APP_ENV

When you call:

$container = $definition->build()

The component will try to get the proper configuration set based on the contents of the variable APP_ENV

There are several ways to set the APP_ENV before start your server:

This can be done using nginx:

fastcgi_param   APP_ENV  dev;


SetEnv APP_ENV dev


    APP_ENV: dev

Docker CLI

docker -e APP_ENV=dev image

Read from a different variable

Instead of use APP_ENV you can set your own variable

$container = $definition

Specify directly

Other way to load the configuration set instead of depending on an environment variable is to specifiy directly which configuration you want to get:

$container = $definition->build("live");

Configuration Files

The config-xxxx.php file



return [
    'property1' => 'string',
    'property2' => true,
    'property3' => function () {
        return 'xxxxxx';
    'propertyWithArgs' => function ($p1, $p2) {
        return 'xxxxxx';



return [
    'property2' => false

The config-xxxx.env file

Alternatively is possible to set an .env file with the contents KEY=VALUE one per line.



By default, all properties are parsed as string. You can parse as bool, int or float as this example:

PARAM1=!bool true
PARAM2=!int 20
PARAM3=!float 3.14

Use in your PHP Code

Create the Definition:

$definition = (new \ByJG\Config\Definition())
    ->withConfigVar('APP_ENV') // This will setup the environment var to 'APP_ENV' (default)
    ->addConfig('homolog')         // This will setup the HOMOLOG configuration set
    ->addConfig('live')            // This will setup the LIVE environenment inherited HOMOLOG
    ->setCache($somePsr16Implementation, 'live'); // This will cache the "live" configuration set. 

The code below will get a property from the defined environment:

$container = $definition->build();
$property = $container->get('property2');

If the property does not exist an error will be thrown.

If the property is a closure, you can call the get method, and you'll get the closure execution result:

$container = $definition->build();
$property = $container->get('closureProperty');
$property = $container->get('closurePropertyWithArgs', 'value1', 'value2');
$property = $container->get('closurePropertyWithArgs', ['value1', 'value2']);

If you want get the RAW value without parse closure:

$container = $definition->build();
$property = $container->raw('closureProperty');

Dependency Injection


It is possible to create a Dependency Injection and set automatically the instances and constructors. Let's get by example the following classes:

namespace Example;

interface Area
    public function calculate();

class Square implements Area
    public function __construct($side)
        // ...

class RectangleTriangle implements Area
    public function __construct($base, $height)
        // ...

We can create a definition for this classes:


use ByJG\Config\DependencyInjection as DI;

return [
    \Example\Square::class => DI::bind(\Example\Square::class)

    \Example\RectangleTriangle::class => DI::bind(\Example\RectangleTriangle::class)
        ->withConstructorArgs([3, 4])

and to use in our code we just need to do:

$config = $definition->build();
$square = $config->get(\Example\Square::class);

Injecting automatically the Objects

Let's figure it out this class:

class SumAreas implements Area
     * SumAreas constructor.
     * @param \DIClasses\RectangleTriangle $triangle 
     * @param \DIClasses\Square $square 
    public function __construct($triangle, $square)
        $this->triangle = $triangle;
        $this->square = $square;


Note that this class needs instances of objects previously defined in our container definition. In that case we just need add this:

return [
    // ....

    SumAreas::class => DI::bind(SumAreas::class)

When use use the method withConstructor() we are expecting that all required classes in the constructor already where defined and inject automatically to get a instance.

This component uses the PHP Document to determine the classed are required.

Get a singleton object

The DependencyInjection class will return a new instance every time you require a new object. However, you can the same object by adding toSingleton() instead of toInstance().

All options (bind)


    // To create a new instance choose *only* one below:
    ->withInjectedConstructor()         // If you want inject the constructor automatically using reflection
    ->withInjectedLegacyConstructor()   // If you want inject the constructor automatically using PHP annotation
    ->withNoConstructor()                // The class has no constructor
    ->withConstructorNoArgs()           // The constructor's class has no arguments
    ->withConstructorArgs(array)        // The constructor's class arguments
    ->withFactoryMethod("method", array_of_args)  // When the class has a static method to instantiate instead of constructure 

    // Call methods after you have a instance
    ->withMethodCall("methodName", array_of_args)
    // How will you get a instance?
    ->toInstance()                   // get a new instance for every container get
    ->toSingleton()                  // get the same instance for every container get 
    ->toEagerSingleton()             // same as singleton however get a new instance immediately  

Use a dependency inject in the config

If you need to use a previously DI created you can use the method use. This method will return a DI instance and allow you to call a method and return its result.

This differs from Param::get because DI::use intends to get a class and return the result of a method call, while Param::get is intended to use as a argument.


    ->withMethodCall("methodName", array_of_args)
    ->toInstance()                   // get the result of the method call

Get the configuration set name is active



composer require "byjg/config=4.1.*"