(四)从零编写PHP容器-添加绑定解析
2020-02-19 本文已影响0人
FinalZero
功能实现
- 代码优化
- 添加绑定解析,优先从绑定实例中获取参数实例
代码实现 Container
use Closure;
use Exception;
use Psr\Container\ContainerExceptionInterface;
use ReflectionClass;
use ReflectionException;
use ReflectionParameter;
class Container
{
/**
* @var array
*/
protected $binds = [];
/**
* @param string $abstract
* @param mixed $instance
* @return $this
*/
public function bind(string $abstract, $instance)
{
$this->binds[$abstract] = $instance;
return $this;
}
/**
* create a new object
* @param string $abstract
* @return Closure|object
* @throws ReflectionException
* @throws Exception
*/
public function create($abstract)
{
return $this->createInstance($abstract);
}
/**
* create new instance
* @param string $abstract
* @param array $tmp
* @return Closure|object
* @throws ReflectionException
* @throws Exception
*/
protected function createInstance(string $abstract, array $tmp = [])
{
if (isset($this->binds[$abstract])) {
return $this->binds[$abstract];
} else if (isset($tmp[$abstract])) {
return $tmp[$abstract];
} else if (array_key_exists($abstract, $tmp)) {
throw new class('can not create a circular dependencies class object.') extends Exception implements ContainerExceptionInterface{ };
} else {
$tmp[$abstract] = null;
}
$refClass = new ReflectionClass($abstract);
if ($refClass->isInterface() || $refClass->isAbstract()) {
throw new class('can not create a class in interface or abstract.') extends Exception implements ContainerExceptionInterface{ };
} elseif ($refClass->getName() === Closure::class) {
return function () {};
} elseif ($refClass->hasMethod('__construct')) {
$_constructParams = array_map(function (ReflectionParameter $param) use ($abstract, $tmp) {
if ($result = $this->paramsHandle($param) instanceof ReflectionClass) {
return $this->createInstance($param->getClass()->getName(), $tmp);
} else {
return $result;
}
}, $refClass->getMethod('__construct')->getParameters());
}
return $tmp[$abstract] = $refClass->newInstance(... ($_constructParams ?? []));
}
/**
* @param ReflectionParameter $param
* @return mixed|ReflectionClass|null
* @throws ReflectionException
*/
private function paramsHandle(ReflectionParameter $param)
{
if ($param->getClass()) {
return $param->getClass();
} elseif ($param->isDefaultValueAvailable()) {
return $param->getDefaultValue();
} elseif ($param->getType()) {
return [
'string' => '',
'int' => 0,
'array' => [],
'bool' => false,
'float' => 0.0,
'iterable' => [],
'callable' => function() {}
][$param->getType()->getName()] ?? null;
} else {
return null;
}
}
}
- 注:
AbsSingleton
为实现单例的抽象类,包含一个getInstance()
静态方法,可忽略
实现思路
实现思路
- 将基础数据类型判断先做分离(方便后期会做基础数据的动态映射)
- 在容器类中添加一个
binds
存储绑定的类 - 在创建方法
createInstance
中读取变量
示例
class E
{
protected $msg;
public function __construct($msg)
{
$this->msg = $msg;
}
public function show()
{
return $this->msg;
}
}
class D
{
protected $e;
public function __construct(E $e)
{
$this->e = $e;
}
public function show()
{
$this->e->show();
}
}
$container = new Container();
$container->bind(E::class, new E('123'));
# 将获取到绑定的`new E('123')`的实例
$e = $container->create(E::class)
$e->show(); // 123
$d = $container->create(D::class)
$d->show(); // 123