Skip to content
Snippets Groups Projects
README.md 3.95 KiB
Newer Older
Thomas Flori's avatar
Thomas Flori committed
# Dependency Injector

Thomas Flori's avatar
Thomas Flori committed
[![build status](https://gitlab.w00tserver.org/tflori/dependency-injector/badges/master/build.svg)](https://gitlab.w00tserver.org/tflori/dependency-injector/commits/master)
Thomas Flori's avatar
Thomas Flori committed
[![Latest Stable Version](https://poser.pugx.org/tflori/dependency-injector/v/stable)](https://packagist.org/packages/tflori/dependency-injector)
[![Total Downloads](https://poser.pugx.org/tflori/dependency-injector/downloads)](https://packagist.org/packages/tflori/dependency-injector)
[![License](https://poser.pugx.org/tflori/dependency-injector/license)](https://packagist.org/packages/tflori/dependency-injector)

Thomas Flori's avatar
Thomas Flori committed
A simple and lightweight dependency injector. You will need nothing more to tests your old legacy code.

Did you ever wondered how complicated it could be to write a dependency injector that works? In fact it is very easy
and you don't need a tons of classes laying around and learn a dozens of new fancy words. 

It is just a storage of functions and values for a specific key. Store your function to create an instance and it get
executed the first time you need this instance.

Sounds to easy? What about dependencies? Check the examples. It is nothing more needed than this.
Thomas Flori's avatar
Thomas Flori committed
 
## Tests

The problem is always to test things and to provide mocks for your tests. This DependencyInjector can solve this
problems. It is possible to call your `getInstance()` method four your singleton like this:
`(DI::get(MySingleton::class))::getInstance()` - now you can provide a mock object under this key.

Thomas Flori's avatar
Thomas Flori committed
## Examples

For examples with tests have a look at the source: tests/examples.

Here are some small examples for basic usage.

Thomas Flori's avatar
Thomas Flori committed
### The `Config`
```php
<?php

use DependencyInjector\DI;

Thomas Flori's avatar
Thomas Flori committed
class Config {
    private static $_instance;
    
    public $database = [
        'host' => 'localhost',
        'user' => 'john',
        'password' => 'does.secret',
        'database' => 'john_doe'
    ];
    
    public $redis = ['host' => 'localhost'];
    
    private function __construct() {
        // maybe some logic to change the config or initialize variables
    }
    
    public static function getInstance() {
        if (!self::$_instance) {
            self::$_instance = new Config();
        }
        return self::$_instance;
    }
}

DI::set('config', function() { return Config::getInstance(); });

function someStaticFunction() {
    // before
    if (empty(Config::getInstance()->database['host'])) {
        throw new Exception('No database host configured');
    }
    
    // now
    if (empty(DI::config()->database['host'])) {
        throw new Exception('No database host configured');
    }
    
    // or if you prefer
    if (empty(DI::get('config')->database['host'])) {
        throw new Exception('No database host configured');
    }
}
```

### The database connection
```php
<?php

use DependencyInjector\DI;

Thomas Flori's avatar
Thomas Flori committed
DI::set('database', function() {
    $dbConfig = DI::config()->database;
    
    $mysql = new mysqli($dbConfig['host'], $dbConfig['user'], $dbConfig['password'], $dbConfig['database']);
    
    if (!empty($mysql->connect_error)) {
        throw new Exception('could not connect to database (' . $mysql->connect_error . ')');
    }
    
    return $mysql;
});

function someStaticFunction() {
    // before it maybe looked like this
    $mysql = MyApp::getDatabaseConnection();
    
    // now
    $mysql = DI::database();
    
    $mysql->query('SELECT * FROM table');
}
```

The problem before: you can not mock the static function `MyApp::getDatabaseConnection()`. You also can not mock the 
static function `DI::database()` or `DI::get('database')`. But you can set the dependency to return a mock object:
Thomas Flori's avatar
Thomas Flori committed

```php
<?php

use DependencyInjector\DI;

Thomas Flori's avatar
Thomas Flori committed
class ApplicationTest extends PHPUnit_Framework_TestCase {
    public function testSomeStaticFunction() {
        $mock = $this->getMock(mysqli::class);
        $mock->expects($this->once())->method('query')
            ->with('SELECT * FROM table');
Thomas Flori's avatar
Thomas Flori committed
        DI::set('database', $mock);
Thomas Flori's avatar
Thomas Flori committed
            
        someStaticFunction();
    }
}
```