Dependency Injection

Post on 13-May-2015

1.841 views 1 download

Tags:

description

Dependency Injection, Reinventing how you manage PHP classes

Transcript of Dependency Injection

Dependency InjectionReinventing how you manage PHP classes

DI?

What is DI?

Dependency Injection means giving an object its instance variables. Really. That's it.

- James Shore

The Really Short Version

Why This Kolaveri DI?

Why This Kolaveri DI?

CHANGE

Why DI?

• Maintainable

• Extendible

• Flexible

• Configurable

• Testable

• Reusable

• Interoperable

A Real Life Example

“Dependency Injection” is a 25-dollar term for a 5-cent concept.

Don’t Panic!

A PHP Example

class MySqlDB {

private $_link;

public function __construct($host, $username, $password, $database) { $this->_link = mysql_connect($host, $username, $password); mysql_select_db($database); }

public function insert($data, $table) { array_map('mysql_real_escape_string', $data); $query = 'INSERT INTO `' . $table . '` (`' . implode('`,`', array_keys($data)) . '`)' . 'VALUES ("' . implode('","', $data) . '" )'; return mysql_query($query, $this->_link); }

// ...

}

define('MYSQL_HOST', 'localhost');define('MYSQL_USER', 'root');define('MYSQL_PASS', '');define('MYSQL_DB', 'test');

class User {

private $_db; private $_info = array();

public function __construct() { $this->_db = new MySqlDB(MYSQL_HOST, MYSQL_USER, MYSQL_PASS,

MYSQL_DB); }

public function register($name, $email, $age, $sex) { $this->_info = compact('name', 'email', 'age', 'sex'); $this->_db->insert($this->_info, 'users'); } // ...}

$user = new User();$user->register('Tasneem', 'tasmee@fb.me', 18, 'female');

// You can hardcode itpublic function __construct() { $this->_db = new MySqlDB('localhost', 'root', '', 'test');}

// You can configure it with an arraypublic function __construct($config) { $this->_db = new MySqlDB($config['host'], $config['user'], $config['pass'], $config['db']);}

// And, What we saw earlierpublic function __construct() { $this->_db = new MySqlDB(MYSQL_HOST, MYSQL_USER, MYSQL_PASS,

MYSQL_DB);}

Options

What if I want to use a different database like MongoDB or SQLite

Hey wait, I can improve it!

class User {

protected $_db; protected $_info = array();

public function __construct() { $registry = RegistrySingleton::getInstance(); $this->_db = $registry->database; }

public function register($name, $email, $age, $sex) { $this->_info = compact('name', 'email', 'age', 'sex'); $this->_db->insert($this->info, 'users'); } // ...

}

$user = new User();$user->register('Tasneem', 'tasmee@fb.me', 18, 'female');

Smart Huh???

So, now User depends on Registry

Let’s do it with DI

class User {

protected $_db; protected $_info = array();

public function __construct($database) { $this->_db = $database; }

public function register($name, $email, $age, $sex) { $this->_info = compact('name', 'email', 'age', 'sex'); $this->_db->insert($this->_info, 'users'); } // ...

}

$mysql = new MySqlDB('localhost', 'root', '', 'test');$user = new User($mysql);$user->register('Tasneem', 'tasmee@fb.me', 18, 'female');

But there are

still rooms for

improvement

Interface

Ever heard ofType Hinting

public function test(OtherClass $otherClass) {

}

public function testInterface(Interface $interface) {

}

public function testArray(array $inputArray) {

}

Type HintingSince PHP 5.1

interface Database { public function insert(array $data, $table);}

class User {

protected $_db; protected $_info = array();

public function __construct(Database $database) { $this->_db = $database; }

public function register($name, $email, $age, $sex) { $this->_info = compact('name', 'email', 'age', 'sex'); $this->_db->insert($this->_info, 'users'); } // ...

}

$mysql = new MySqlDB('localhost', 'root', '', 'test');$user = new User($mysql);$user->register('Tasneem', 'tasmee@fb.me', 18, 'female');

class MySqlDB implements Database {

protected $_link;

public function __construct($host, $username, $password, $database) { $this->_link = mysql_connect($host, $username, $password); mysql_select_db($database); }

public function insert(array $data, $table) { array_map('mysql_real_escape_string', $data); $query = 'INSERT INTO `' . $table . '` (`' . implode('`,`', array_keys($data)) . '`)' . 'VALUES ("' . implode('","', $data) . '" )'; return mysql_query($query, $this->_link); }

// ...}

MySQL

class MongoDB implements Database {

// ...

public function insert(array $data, $table) { // Save the passed array using MongoDB }

// ...

}

$mongoDb = new MongoDB('localhost', 'root', '', 'test');$user = new User($mongoDb);$user->register('Tasneem', 'tasmee@fb.me', 18, 'female');

MongoDB

class SQLiteDB implements Database {

// ...

public function insert(array $data, $table) { // Save the passed array using SQLite }

// ...

}

$sqlite = new SQLiteDB('app.db', 'test');$user = new User($sqlite);$user->register('Tasneem', 'tasmee@fb.me', 18, 'female');

SQLite

class TestDB implements Database {

protected $_data = array();

public function insert(array $data, $table) { $this->_data[$table] = $data; } public function get($table) { return $this->_data[$table]; }

}

$fakeDb = new TestDB();$user = new User($fakeDb);$user->register('Tasneem', 'tasmee@fb.me', 18, 'female');print_r($fakeDb->get('users'));

TestDB

DI Container

class Container { protected $s=array(); function __set($k, $c) { $this->s[$k]=$c; } function __get($k) { return $this->s[$k]($this); }}

TwitteeA DI Container in a Tweet

using the power of PHP 5.3

$c = new Container();

$c->mysql = function ($c) { return new MySqlDB('localhost', 'root', '', 'test');}

$c->user = function ($c) { $db = $c->mysql; return new User($db);}

// When you need a user$user = $c->user;

// Instead of$user = new User();

Container

Question?