mcustiel/php-simple-di

Minimalist library to manage dependency injection with low memory usage and high performance.

1.2.1 2015-01-06 14:12 UTC

This package is auto-updated.

Last update: 2024-04-19 08:35:25 UTC


README

What is it?

php-simple-di (Php Simple Dependency Injection) is a library that provides a minimalistic dependency container with the ability to provide singleton or prototype versions of the dependencies identifying them by a name. php-simple-di provides a singleton class where you can register your dependencies, indentifying them by a name and then you can retrieve them. This library only creates instances on demand (it does not instanciate dependencies that are not needed for a request execution), so you only process and have in memory what you are using.

Installation

Composer:

{
    "require": {
        // ...
        "mcustiel/php-simple-di": "^1.2.1"
    }
}

How to use it?

Registering

In your bootstrap file (or some startup script) you must define all the possible dependencies that your classes might need.

use Mcustiel\DependencyInjection\DependencyInjectionService;

$dependencyInjectionService = new DependencyInjectionService();
// ...
$dbConfig = loadDbConfig();
$cacheConfig = loadCacheConfig();
$dependencyInjectionService->register('dbConnection', function() use ($dbConfig) {
    return new DatabaseConnection($dbConfig);
});
$dependencyInjectionService->register('cache', function() use ($cacheConfig) {
    return new CacheManager($cacheConfig);
});

Getting dependencies

Then you can retrieve instances by refering them through their identifier.

$cacheManager = $dependencyInjectionService->get('cache');

Instances

php-simple-di creates "singleton" instances by default, this means everytime you request for a dependency it will return the same instance every time. If by any chance you need to change this behavior, you can define that every time you asks php-simple-di for a dependency it will return a new instance. This behavior is changed through a boolean parameter in register method.

Singleton behavior

$dependencyInjectionService->add('dbConnection', function() use ($dbConfig) {
    return new DatabaseConnection($dbConfig);
});
// or also you can make it explicit:
$dependencyInjectionService->register('cache', function() use ($cacheConfig) {
    return new CacheManager($cacheConfig);
}, true);

$instance1 = $dependencyInjectionService->get('cache');
$instance2 = $dependencyInjectionService->get('cache');
// $instance1 and $instance2 reference the same object

Prototype behavior

$dependencyInjectionService->register('dbConnection', function() use ($dbConfig) {
    return new DatabaseConnection($dbConfig);
}, false);

$instance1 = $dependencyInjectionService->get('cache');
$instance2 = $dependencyInjectionService->get('cache');
// $instance1 and $instance2 reference different objects

Notes

To simplify the previous examples I've shown config as previously obtained, but php-simple-di is perfectly capable of enclosing that functionality inside callbacks, even calling itself:

$dependencyInjectionService->add('config-loader', function() {
    return new SomeConfigLoaderService();
});

$dependencyInjectionService->add('config', function() {
    $injector = new DependencyInjectionService();
    $configLoader = $injector->get('config-loader');
    return $configLoader->load();
});

$dependencyInjectionService->add('dbConnection', function() {
    $injector = new DependencyInjectionService();
    $dbConfig = $injector->get('config');
    return new DatabaseConnection($dbConfig);
});

There's a lot of discussion around Singleton pattern, mentioning it as an antipattern because it's hard to test. Anyway, php-simple-di provides the container as a singleton class to allow just a single instance to be part of the execution. You should think in good practices and avoid using this class through singleton, but define it in your bootstrap file and pass the container instance as a parameter to your application dispatcher and always pass it as a parameter (injecting it as a dependency). Then, remember to use it properly, don't pass the container as a dependency, but use it to obtain the dependencies and pass them to your services.

// Do this:
$dbConnection = $dependencyInjectionService->get('dbConnection');
$personDao = new PersonDao($dbConnection); // Pass the proper dependency
// Instead of doing this:
$personDao = new PersonDao($dependencyInjectionService); // This works but is heretic and makes a little kitten cry.