Skip to content

Instantly share code, notes, and snippets.

@anothergituser
Created June 24, 2012 23:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anothergituser/2985388 to your computer and use it in GitHub Desktop.
Save anothergituser/2985388 to your computer and use it in GitHub Desktop.
PHP 5.3 Lightweight IOC container
<?php
/*
* Lightweight IOC container
*/
class IOC {
// if a hinted class name is matched here
// use the associated value as the new class
private $constraints = array();
// object cache
private $cache;
private $objectCache = array();
public function __construct($cache = false) {
$this->cache = $cache;
}
public function forClass($originalHinted, $newClass) {
if (!array_key_exists($originalHinted, $this->constraints)) {
$this->constraints[$originalHinted] = $newClass;
}
}
public function make($object) {
// parameters for the construct of object
$objectParameters = array();
// all the arguments passed to make
// can be of any type
$args = func_get_args();
// skip the object name for the other types of parameters
array_shift($args);
if (is_string($object) && class_exists($object)) {
// defining class for the object we try to make
$ref = new ReflectionClass($object);
// object constructor
$constructor = $ref->getConstructor();
if ($constructor) {
// constructor parameters
$constructorParameters = $constructor->getParameters();
$otherTypeParameterCounter = 0; // incremented only when the type of the arg is not a class
foreach ($constructorParameters as $parameter) {
// the parameter should be an instance of the hinted class
$hintedClass = $parameter->getClass();
if ($hintedClass != NULL) {
$hintedClassName = $hintedClass->getName();
// overridden hinted class
if (array_key_exists($hintedClassName, $this->constraints)) {
$hintedClassName = $this->constraints[$hintedClassName];
}
// instantiate the class and add it to the
// parameters list
if (class_exists($hintedClassName)) {
// the hinted class could have hinted class parameters and other types as well
$objectParameters[] = $this->make($hintedClassName);
}
} else {
// other type of parameter
// found in the args array
// these parameters are passed to the make function after
// the object to create
$objectParameters[] = $args[$otherTypeParameterCounter];
$otherTypeParameterCounter++;
}
}
}
if (empty($objectParameters)) {
if ($this->cache) {
$objectIdentifier = $ref->name;
if (array_key_exists($objectIdentifier, $this->objectCache)) {
return $this->objectCache[$objectIdentifier];
} else {
$o = new $object;
$this->objectCache[$objectIdentifier] = $o;
return $o;
}
} else {
return new $object;
}
} else {
if ($this->cache) {
$objectIdentifier = $ref->name . md5(serialize($objectParameters));
if (array_key_exists($objectIdentifier, $this->objectCache)) {
return $this->objectCache[$objectIdentifier];
} else {
$o = $ref->newInstanceArgs($objectParameters);
$this->objectCache[$objectIdentifier] = $o;
return $o;
}
} else {
return $ref->newInstanceArgs($objectParameters);
}
}
} else {
die("Invalid use of IOC, $object is not a class.");
}
}
}
object(SteelDoor)[12]
private 'material' =>
object(Steel)[13]
private 'materialName' (Material) => string 'steel' (length=5)
private 'strength' => int 5
object(WoodWindow)[14]
private 'material' =>
object(Wood)[15]
private 'materialName' (Material) => string 'wood' (length=4)
object(ReinforcedSteelDoor)[17]
private 'material' (SteelDoor) =>
object(Steel)[18]
private 'materialName' (Material) => string 'steel' (length=5)
private 'strength' (SteelDoor) => int 10
object(WoodWindow)[19]
private 'material' =>
object(Wood)[20]
private 'materialName' (Material) => string 'wood' (length=4)
<?php
require_once 'ioc.class.php';
class Material {
private $materialName = null;
public function __construct() {
}
public function setMaterialName($name) {
$this->materialName = $name;
}
public function getMaterialName() {
return $this->materialName;
}
}
class Wood extends Material {
public function __construct() {
parent::__construct();
$this->setMaterialName("wood");
}
}
class Steel extends Material {
public function __construct() {
parent::__construct();
$this->setMaterialName("steel");
}
}
class WoodWindow {
private $material;
public function __construct(Wood $material) {
$this->material = $material;
}
public function getWindowMaterial() {
return $this->material->getMaterialName();
}
}
class SteelDoor {
private $material;
private $strength = 5;
public function __construct(Steel $material) {
$this->material = $material;
}
public function getDoorMaterial() {
return $this->material->getMaterialName();
}
public function setStrength($strength) {
$this->strength = $strength;
}
}
class ReinforcedSteelDoor extends SteelDoor {
public function __construct(Steel $material) {
parent::__construct($material);
$this->setStrength(10);
}
}
class House {
private $door;
private $window;
public function __construct(SteelDoor $door, WoodWindow $window) {
$this->door = $door;
$this->window = $window;
}
public function describe() {
var_dump($this->door);
var_dump($this->window);
}
}
$ioc = new IOC(); // pass true to the constructor for object caching
$house = $ioc->make("House");
$house->describe();
// how about a better door
// just override the used class for the steel door
$ioc->forClass("SteelDoor", "ReinforcedSteelDoor");
$house = $ioc->make("House");
$house->describe();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment