Last active
April 20, 2017 00:31
-
-
Save haruair/9f1a9ddb8927f1aeb6823c4bc948aee1 to your computer and use it in GitHub Desktop.
small DI classes
This file contains 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 | |
namespace Wattle\DI; | |
use ReflectionClass; | |
use Exception; | |
use Closure; | |
/** | |
* Scope Implementation. | |
*/ | |
class Scope | |
{ | |
protected $container; | |
protected $scope = []; | |
/** | |
* Initializes a new instance of the Scope class. | |
* | |
* @param Container $container | |
*/ | |
public function __construct(Container $container) | |
{ | |
$this->container = $container; | |
} | |
/** | |
* Resolve an instance based on the name of the type. | |
* | |
* @param string $typeName | |
* @return object | |
* @throws DependencyResolutionException | |
*/ | |
public function resolve(string $typeName) | |
{ | |
if ($this->isDisposed()) { | |
throw new DependencyResolutionException('Scope is already disposed'); | |
} | |
return $this->createInstance($typeName); | |
} | |
/** | |
* Create the requested instances. | |
* | |
* Initializing the instance with required constructor params. It iterrates | |
* if the resolving required. | |
* | |
* @param string $typeName | |
* @param boolean $initial | |
* @return object | |
*/ | |
protected function createInstance(string $typeName, $initial = true) | |
{ | |
if (! $initial && $this->container->has($typeName)) { | |
$typeName = $this->container->has($typeName); | |
} | |
if (array_key_exists($typeName, $this->scope)) { | |
return $this->scope[$typeName]; | |
} else { | |
$cls = new ReflectionClass($typeName); | |
$ref = $cls->getConstructor(); | |
$args = []; | |
if ($ref) { | |
$params = $ref->getParameters(); | |
if (count($params) > 0) { | |
foreach ($params as $param) { | |
$type = $param->getType(); | |
$args[] = $this->createInstance($type, false); | |
} | |
} | |
} | |
$obj = $cls->newInstanceArgs($args); | |
$this->scope[$typeName] = $obj; | |
return $obj; | |
} | |
} | |
/** | |
* Dispose the scope. | |
* | |
* @return void | |
* @throws DependencyResolutionException | |
*/ | |
public function dispose() | |
{ | |
if ($this->isDisposed()) { | |
throw new DependencyResolutionException('Scope is already disposed'); | |
} | |
unset($this->scope); | |
unset($this->container); | |
} | |
/** | |
* Returns true if it is disposed. | |
* | |
* @return boolean | |
*/ | |
public function isDisposed() | |
{ | |
return !isset($this->container); | |
} | |
} | |
/** | |
* Container implementation. | |
*/ | |
class Container | |
{ | |
protected $resolves; | |
/** | |
* Default scope for the container itself. | |
* @var Scope | |
*/ | |
protected $rootScope; | |
/** | |
* Initializes new Container. | |
* | |
* @param array $resolves | |
*/ | |
public function __construct(array $resolves) | |
{ | |
$this->resolves = $resolves; | |
$this->rootScope = new Scope($this); | |
} | |
/** | |
* Create the scope inside the closure which is provided. | |
* | |
* It returns the result of the closure. | |
* | |
* @param Closure $closure | |
* @return mixed | |
*/ | |
public function scope(Closure $closure) | |
{ | |
$scope = $this->createScope(); | |
$result = $closure($scope); | |
$scope->dispose(); | |
return $result; | |
} | |
/** | |
* Create new Scope. | |
* | |
* @return Scope | |
*/ | |
public function createScope() | |
{ | |
return new Scope($this); | |
} | |
/** | |
* Check the resolve exists in the resolution mapping. | |
* | |
* @param string $key | |
* @return boolean | |
*/ | |
public function has(string $key) | |
{ | |
return array_key_exists($key, $this->resolves) ? $this->resolves[$key] : false; | |
} | |
/** | |
* Create the requested instances via rootScope. | |
* | |
* Initializing the instance with required constructor params. It iterrates | |
* if the resolving required. | |
* | |
* @param string $typeName | |
* @param boolean $initial | |
* @return object | |
*/ | |
public function resolve(string $typeName) | |
{ | |
return $this->rootScope->resolve($typeName); | |
} | |
/** | |
* Dispose the root scope. | |
* | |
* @return void | |
* @throws DependencyResolutionException | |
*/ | |
public function dispose() | |
{ | |
return $this->rootScope->dispose(); | |
} | |
/** | |
* Returns true if the rootScope is disposed. | |
* | |
* @return boolean | |
*/ | |
public function isDisposed() | |
{ | |
return $this->rootScope->isDisposed(); | |
} | |
} | |
/** | |
* ContainerBuilder implementation. | |
*/ | |
class ContainerBuilder | |
{ | |
/** | |
* Stores resolving mapped array. | |
* | |
* @var array | |
*/ | |
protected $resolves = []; | |
/** | |
* Register the type via chaining ContainerBuilderAs class. | |
* | |
* @param string $typeName | |
* @return ContainerBuilderAs | |
*/ | |
public function registerType(string $typeName) | |
{ | |
return new ContainerBuilderAs($this, $typeName); | |
} | |
/** | |
* Register the target type and binded type. | |
* | |
* @param string $targetTypeName | |
* @param string $bindTypeName | |
* @return void | |
*/ | |
public function register(string $targetTypeName, string $bindTypeName) | |
{ | |
$this->resolves[$targetTypeName] = $bindTypeName; | |
} | |
/** | |
* Returns container using the resolves. | |
* | |
* @return Container | |
*/ | |
public function build() | |
{ | |
return new Container($this->resolves); | |
} | |
} | |
/** | |
* ContainerBuilderAs implmentation. | |
* | |
* It provides chaining method for the convenience. | |
*/ | |
class ContainerBuilderAs | |
{ | |
protected $builder; | |
protected $typeName; | |
/** | |
* Initializes ContainerBuilderAs. | |
* | |
* @param ContainerBuilder $builder | |
* @param string $typeName | |
*/ | |
public function __construct(ContainerBuilder $builder, string $typeName) | |
{ | |
$this->builder = $builder; | |
$this->typeName = $typeName; | |
} | |
/** | |
* Register the type for the following type name. | |
* | |
* It returns itself for the chaining. | |
* | |
* @param string $typeName | |
* @return ContainerBuilderAs | |
*/ | |
public function asType($typeName) | |
{ | |
$this->builder->register($typeName, $this->typeName); | |
return $this; | |
} | |
/** | |
* Register the type for the type itself. | |
* | |
* It returns itself for the chaining. | |
* | |
* @return ContainerBuilderAs | |
*/ | |
public function asSelf() | |
{ | |
$this->builder->register($this->typeName, $this->typeName); | |
return $this; | |
} | |
} | |
/** | |
* Default exception type thrown whenever the dependency resolving process fails. | |
*/ | |
class DependencyResolutionException extends Exception | |
{ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment