Skip to content
Snippets Groups Projects
user avatar
Thomas Flori authored
658d51da

Dependency Injector

A simple and lightweight dependency injector. You will need nothing more to tests your old legacy code.

What is a dependency

Something that your script needs to work correct. For example an instance of Calculator or Config. Or even a class itself.

Examples

The Config

<?php

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;
    }
}

class_alias('DependencyInjector', 'DI'); // create an alias for easier access

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

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:

<?php

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