Intro

DiMaria is a Dependency Injection Container for PHP 7 with no dependencies. It's written to be extremely fast and lightweight.

Installation

Fetch DiMaria with composer via packagist. Add it with composer require dangerousdan/dimaria

Usage

DiMaria should work out of the box. Just call get() with the class name you wish to create.
$di = new DD\DiMaria;
$object = $di->get('ClassName');
DiMaria implements the container-interop interface.

Default Behaviour

Classes are fetched with either the get or create method. The get method will fetch a class and also cache the response for later use. This means that fetching the same class again will return the exact same instance. The create method will fetch a new instance of the class each time. If a class has type-hinted parameters on its constructor then these will automatically be fetched, resolving all the dependencies down the chain. This is done by internally calling the create method.

Configuring Classes

If a constructor parameter is not type-hinted or optional, then you will need to tell DiMaria which parameters to use. This is done with the setParams method. setParams takes two arguments: the class name, and a key-value array of parameters. Only the parameters that you wish to set need to be entered. If a parameter is optional, or type-hinted then it is okay to leave this blank.

$di = new DD\DiMaria;
$di->setParams('DbStorage', [
    'username' => 'readAccess',
    'password' => 'abcd',
    'server' => 'localhost'
]);    

If you want to pass a class as a parameter then it is possible to do this using ['instanceOf' => 'ClassName']. It is also possible to set or override parameters during object creation. This is done by passing the key-value array of parameters to the get or create method.

$di = new DD\DiMaria;
$di->setParams('Repository', [
    'storage' => [
        'instanceOf' => 'DbStorage'
    ],
    'mapper' => [
        'instanceOf' => 'Mapper',
        'params' => [
            'foo' => 'bar'
        ]
    ]
]);
$object = $di->get('Repository');

Aliasing

Aliases are set in the same was as setParams, except we also set the name of the alias. Setting parameters on aliases is optional. Any parameters set will override any existing parameters set on that class. Aliases are useful if you require the same class to be used in two different ways. Eg. A Database class that connects to two separate databases.

It is also possible to alias an alias. Parameters are merged together. The 'outer' alias parameters will take precedence. Any parameters which are set when calling get or create will override any alias config

$di = new DD\DiMaria;
$di->setParams('DbStorage', [
    'username' => 'readAccess',
    'password' => 'abcd',
    'server' => 'localhost'
]);
$di->setAlias('DbStorageWithWritePermissions', 'DbStorage', [
    'username' => 'writeAccess',
    'password' => '1234'
]);

$readStorage = $di->get('DbStorage');
$writeStorage = $di->get('DbStorageWithWritePermissions');

Preferences

Setting preferences allows us to set a preferred implementation of an instance or class. Any class parameter that requires that instance or class will then be given the preferred implementation of it. SetPreference can easily be overridden be explicitly defining which class to pass to a parameter.

$di = new DD\DiMaria;
$di->setPreference('StorageInterface', 'DbStorage');
$repository = $di->get('Repository');

Shared Instances

By default, get will return a shared instance, and create will not. This behaviour can be overridden with setShared('classOrAlias', bool) Internally, class dependencies are fetched with 'create', so marking a class as shared is useful if a class dependency should be a shared instance. Also, marking a class as not shared will overwrite the default get behaviour and return a new instance each time. This is useful for interoperability.

$di = new DD\DiMaria;

$di->setShared('ClassName');
$object1 = $di->create('ClassName');
$object2 = $di->create('ClassName');

$di->setShared('ClassName', false);
$object3 = $di->get('ClassName');
$object4 = $di->get('ClassName');

In this example, $object1 and $object2 are the same instance, even though the create method is used. $object3 and $object4 are different instances.

Variadics

Setting variadic parameters is similar to how we set normal parameters, except we pass a multidimensional array. Variadic parameters will work with aliases and shared instances. Variadic functions cannot have a default value, but they are always optional. If no value is set, a variadic parameter will be given an empty array.

$di = new DD\DiMaria;
$di->setAlias('RedBall', 'Ball', ['colour' => 'red']);
$di->setParams('Ballpool', [
    'height' => 20,
    'balls' => [
        ['instanceOf' => 'Ball'],
        ['instanceOf' => 'Ball'],
        ['instanceOf' => 'RedBall']
    ]
]);
$ballpool = $di->get('Ballpool', [
    'width' => 5
]);

Setter Injection

Class methods can be configured to be automatically called during object creation. Setter rules are appended rather than overwritten. This makes it possible to call the same setter multiple times. Injection rules are not inherited from other classes or aliases. They only apply to the class or alias in the rule.

$di = new DD\DiMaria;
$di->setInjection('Foo', 'doSomething');
$di->setInjection('Foo', 'doSomething', ['bar' => true]);
$foo = $di->get('Foo');

Custom Values

It is possible to set a value by calling set. This value is retrievable by using 'get'. Any value that is set is inserted into its cache and therefore overrides any existing class or alias. This means DiMaria can operate effectively as a simple key-value store.

$di = new DD\DiMaria;
$di->set('name', 'DangerousDan');
$myName = $di->get('name');

DiMaria also allows custom factories using setFactory. Internally, DiMaria will create a factory for each class that it inspects, so that it can quickly create another instance of that class. setFactory allows us to set our own callable as a factory, which will be retrievable by calling 'create'.

$di = new DD\DiMaria;
$di->setFactory('name', function() use ($di) {
    $service = $di->get('myService');
    return $service->getName();
});
$myName = $di->get('name');

Methods

get

public function get($class, array $params = [])
The get method is used to fetch an instance of a class. If the class has been fetched before, then it will return a cached instance.
If dependencies need to be calculated internally then these will be created usig the createmethod.
It is possible to override the default cache behaviour by marking the class an not shared with the setShared method

create

public function create(string $class, array $params = [])
The get method is used to fetch an instance of a class. This differs from get in that it will always return a new instance of a class.

has

public function has($class): bool
The has method will return a boolean which represents whether the class passed to it is fetchable.
This is determined by checking if the class exists, or whether the value passed matches an existing alias, preference or cached instance

setParams

public function setParams(string $class, array $params): self
The setParams allows setting or overriding default parameters on classes.
The method returns $this to allow for a fluent interface

setAlias

public function setAlias(string $alias, string $class, array $params = []): self;
setAlias will create an alias of a class which can later be fetched using the get or create methods.
The method functions similarly to setParams except we also pass the name of the alias, and the parameters are now optional.
Parameters set on the class will be inherited by the alias. Any parameters set on the alias will not affect the original class.

setPreference

public function setPreference(string $alias, string $class): self
setPreference allows setting a preferred implementation of a class or interface.
If a class parameter is typehinted to a class or interface, it will use the preferred implementation instead.

setShared

public function setShared(string $class, bool $isShared = true): self
setShared allows you to change the default caching behaviour of theget or create methods. By default, get will cache the result, and create will not.

This is useful for 2 reasons.
#1 The get method uses create internally to fetch its dependencies. If one of those dependencies should be shared, then it is possible to do this using this method.
#2 DiMaria implements the container-interop ContainerInterface for container interoperabilty. This requires a container has a get and a has method. Setting a class to be not shared allows us to create a new instance each time using the get method, therefore allowing full interoperabilty.

setInjection

public function setInjection(string $class, string $method, array $params = []): self
setInjection allows us to automatically call a method on the object before returning it. Method parameters are passed in an associated array.
Injections rules are appended, not overwritten. This allows us to call the same method multiple times.
Any Injection rules are not inherited when by aliases of the method.

set

public function set(string $key, $value): self
The set method allows you to set any custom values. The values are stored in the cache and retrievable with the get method.

setFactory

public function setFactory(string $key, callable $factory): self
The setFactory method allows you to set a custom callable, which is retrievable by the get or create method.
Note: The get method will also return the result of the callable, but subsequent calls will return the same cached result.