Skip to content

Instantly share code, notes, and snippets.

@DavertMik
Created February 29, 2012 01:40
Show Gist options
  • Save DavertMik/1936860 to your computer and use it in GitHub Desktop.
Save DavertMik/1936860 to your computer and use it in GitHub Desktop.
Dependency Management Concept. RFC

This is about getting rid of Dependency Injection Container and DI practices taken from Java. Good bye Java, viva la PHP!

We start with common example. Session.

<?php

class SessionStorage {

 	function __construct() 
 	{ 
 		session_name('PHP_SESS_ID'); 
 		session_start(); 
 	} 

 	function set($key, $value) { 
 		$_SESSION[$key] = $value; 
 	}
}

class User {
	function __construct()
	{
		$this->storage = new SessionStorage;
	}
}

?>

Usage of this User class is pretty simple.

<?php
$user = new User();
?>

Dependency is not injected. Everything is hardocded. And that's cool, 'cause it works and is simple as a table.

When we want to remove some hardcoded values, let's think of small refactor. Every time we come to thought that some hardcoded thing should be extended, we refactor code. Right? Let's say we want add more storages.

<?php

interface Storage {

   function get() {}
   function set() {}
}

class CookieStorage implements Storage {

 	function __construct() 
 	{ 
 		session_name('PHP_SESS_ID'); 
 		session_start(); 
 	} 

 	function set($key, $value) { 
 		$_SESSION[$key] = $value; 
 	}
}

class MySQLStorage implements Storage {

 	function __construct() 
 	{ 
 		$this->con = new PDO('');
 	} 

 	function get() {
 		// todo
 	}

 	function set()
 	{
 		// todo
 	}

}

class SessionStorage extends CookieStorage implements Storage {

}

class User {
	function __construct()
	{
		$this->storage = new SessionStorage;
	}
}

?>

This change shows that we made a SessionStorage to use CookieStorge. We can easily change implementation of SessionStorage by switiching between MySQLStorage and CookieStorage. Please, note that this change doesn't affect the User class.

User class is still easy to use. We have no Dependency Injection here. The only problem everything is funcking hardcoded. To change the Storage we should edit the SessionStorage class, to change cookie name we should edit CookieStorage class, and MySQLStorage needs parameter for database access...

Ok, what we should do? Refactor it!

<?php

class CookieStorage {

 	function __construct() 
 	{ 
 		session_name(%name%); 
 		session_start(); 
 	} 

 	function set($key, $value) { 
 		$_SESSION[$key] = $value; 
 	}
}

class MySQLStorage implements Storage {

 	function __construct() 
 	{ 
 		$this->con = new PDO(%dsn%);
 	} 

 	function get() {
 		// todo
 	}

 	function set()
 	{
 		// todo
 	}

}

class SessionStorage extends %storage% implements ArrayAccess {

}

class User {
	function __construct()
	{
		$this->storage = new SessionStorage;
	}
}

?>

We walked through classes and replaced all hardcoded things with %variables%. Well, we totally broke the code. It won't compile anymore. It's not a valid PHP file, but a template.

Yep, it's a template. When we come to thought that there are some hardcodes that might be changed, let's move class from template and replace all hardcoded places with variables. Then we will should use a configuration file and a compiler which will build classes from templates and configuration.

To get the classes we had before we can use this configuration file.

CookieStorage:
	vars:
		name: PHP_SESS_ID

MeSQLStorage:
	vars:
		dsn: mysql:localhost

SessionStorage:
	vars:
		storage: CookieStorage				

By moving this variables into configuration we can easily change the Storage backend. Change storage var of SessionStorage class and rebuild classes. This we can easily move from MySQL to cookie and vice versa. A SessionStorage has no magic inside it. It just extends the class you defined. It's easy to use it's methods.

Why that's better then common Dependency Injection?

When you develop you should not think on any injection or configuration. You just write the code! Then when time comes and functionality should be extended you introduce configuration, move everything to templates, and compile. Thus, you solve problems only when you meet them. No more abstractions before they needed.

No more magic!

When you work with User object you will work with one or another SessionStorage implementations. And that's quite useful as you can introspect this class, see all it's methods and variables. Autocompletion in your IDE will work perfectly.

Build, not Inject!

In the end we've implemented Dependency Management, configuration of classes, but the final user class is still as easy to use as it was.

<?php
$user = new User();
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment