Skip to content

Instantly share code, notes, and snippets.

@haruair
Last active April 20, 2017 00:31
Show Gist options
  • Save haruair/9f1a9ddb8927f1aeb6823c4bc948aee1 to your computer and use it in GitHub Desktop.
Save haruair/9f1a9ddb8927f1aeb6823c4bc948aee1 to your computer and use it in GitHub Desktop.
small DI classes
<?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