Last active
August 29, 2015 14:14
-
-
Save moon0326/35becfa058e4358272c0 to your computer and use it in GitHub Desktop.
Simple PHP DI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Container | |
{ | |
protected $index = array(); | |
const TYPE_SINGLETON = 'singleton'; | |
const TYPE_INSTANCE = 'instance'; | |
const TYPE_BIND = 'bind'; | |
public function make($abstract) | |
{ | |
if ($this->has($abstract)) { | |
$data = &$this->index[$abstract]; | |
switch ($data['type']) { | |
case static::TYPE_INSTANCE: | |
return $data['concret']; | |
break; | |
case static::TYPE_SINGLETON: | |
if ($data['singleton'] === null) { | |
$data['singleton'] = $data['concret'](); | |
} | |
return $data['singleton']; | |
break; | |
case static::TYPE_BIND: | |
return $this->resolve($data['concret']); | |
break; | |
} | |
} else { | |
return $this->resolve($abstract); | |
} | |
} | |
protected function resolve($concret) | |
{ | |
$reflector = new ReflectionClass($concret); | |
$method = $reflector->getConstructor(); | |
// the class doesn't have a cosntructor | |
if (is_null($method)) { | |
return new $concret(); | |
} | |
$dependencies = $method->getParameters(); | |
$parameters = array(); | |
foreach ($dependencies as $dependency) { | |
$dependencyClass = $dependency->getClass(); | |
if (!$dependencyClass) { | |
continue; | |
} else { | |
$dependencyClass = $dependencyClass->name; | |
} | |
if ($this->has($dependencyClass)) { | |
$dependencyObject = $this->make($dependencyClass); | |
} else { | |
$dependencyObject = $this->resolve($dependencyClass); | |
} | |
array_push($parameters, $dependencyObject); | |
} | |
return $reflector->newInstanceArgs($parameters); | |
} | |
public function has($key) | |
{ | |
return array_key_exists($key, $this->index); | |
} | |
protected function register($abstract, $concret, $type) | |
{ | |
if (!is_string($abstract) && !is_callable($concret)) { | |
throw new InvalidArgumentException("binding name must be a string or callable object."); | |
} | |
if ($this->has($abstract)) { | |
throw new InvalidArgumentException($abstract." is already binded."); | |
} | |
$this->index[$abstract] = array( | |
'type' => $type, | |
'concret' => $concret, | |
); | |
if ($type == static::TYPE_SINGLETON) { | |
$this->index[$abstract]['singleton'] = null; | |
} | |
} | |
public function bind($abstract, $concret) | |
{ | |
$this->register($abstract, $concret, static::TYPE_BIND); | |
} | |
public function singleton($abstract, $concret) | |
{ | |
$this->register($abstract, $concret, static::TYPE_SINGLETON); | |
} | |
public function instance($abstract, $concret) | |
{ | |
$this->register($abstract, $concret, static::TYPE_INSTANCE); | |
} | |
} | |
// Interface binding | |
interface Emailer {} | |
class SwiftMailer implements Emailer {} | |
$container = new Container(); | |
$container->bind('Emailer', 'SwiftMailer'); | |
// Autowire/Automatic Resolution | |
class Food { } | |
class Human | |
{ | |
private $food; | |
public function __construct(Food $food) | |
{ | |
$this->food = $food; | |
} | |
} | |
$human = $container->make('Human'); | |
// Singleton | |
$container->singleton('Human', function() { | |
return new Human(new Food); | |
}); | |
var_dump($container->make('Human') === $container->make('Human')); | |
// Instance Binding | |
$human = new Human(new Food); | |
$container->instance('Human', $human); | |
var_dump($human === $container->make('Human')); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment