您的位置:首页 > 编程语言 > PHP开发

204 IOC 仿照laravel实现一个最简容器 2

2016-10-25 23:40 393 查看

仿照laravel实现一个最简容器 2

一、闭包实现bind

由此我们实现了容器的核心功能

<?php

class Ioc{
protected $bindings = [];

function bind($abstract,$concrete = null,$shared = 0){
echo "step bind   abstract : [$abstract] <br/>";
if (!$concrete instanceof Closure){
$concrete = $this->getClosure($abstract,$concrete);
}

// $this->bindings[$abstract] = compact($concrete,$share);
$this->bindings[$abstract] = compact('concrete','shared');

}

function getClosure($abstract,$concrete){

return function ($c) use ($abstract,$concrete){

echo "step getClosure   abstract : [$abstract] , concrete : [$concrete] <br/>";

$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete);
};
}

function make($abstract){
$concrete = $this->getConcrete($abstract);

echo "step make  abstract : [$abstract] , abstract : [$abstract] <br/>";
if ($this->isBuildable($concrete,$abstract)){
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
return $object;

}

public function getConcrete($abstract){
echo "step getConcrete  abstract : [$abstract] <br/>";

if (isset($this->bindings[$abstract])){
// var_dump($this->bindings[$abstract]['concrete']);
// 这里会返回bind的时候绑定的闭包,但是闭包未被调用
return $this->bindings[$abstract]['concrete'];
}

return $abstract;
}

public function isBuildable($concrete,$abstract){
return $abstract === $concrete || $concrete instanceof Closure;
}

function build($concrete){
if ($concrete instanceof Closure){
echo "step build  <br/>";
} else {
echo "step build  concrete : [$concrete] <br/>";
}

if ($concrete instanceof Closure){
//到这里getClosure 才第一次被执行
return $concrete($this);
}

//下面的情况应该是对应 $abstract == $concrete
$reflector = new ReflectionClass($concrete);
if (! $reflector->isInstantiable()){
echo $message = "target [$concrete] is not isInstantiable";
}

$constructor = $reflector->getConstructor();
if (is_null($constructor)){
return new $concrete;
}
$dependencies = $constructor->getParameters();
$instances = $this->getDependencies($dependencies);
return $reflector->newInstanceArgs($instances);
}

function getDependencies($parameters){
$dependencies = [];
foreach ($parameters as $parameter) {
$dependency = $parameter->getClass();
if (is_null($dependency)){
$dependencies[] = null;
} else {
$dependencies[] = $this->resolveClass($parameter);
}
}
return (array)$dependencies;
}

function resolveClass( ReflectionParameter $parameter){
return $this->make($parameter->getClass()->name);
}
}

interface Tool{
function go();
}

class Train implements Tool{
function go(){
echo "drive to tibet";
}
}

$app = new ioc();
$app->bind('tool','Train');
$tool = $app->make('tool');


二、分析下执行流程

上面的代码执行之后会得到如下结果

step bind abstract : [tool]
step getConcrete abstract : [tool]
step make abstract : [tool] , abstract : [tool]
step build
step getClosure abstract : [tool] , concrete : [Train]
step getConcrete abstract : [Train]
step make abstract : [Train] , abstract : [Train]
step build concrete : [Train]


1.首先是
Bind()

我们bind的是字符串,所以会调用
getClosure


return function ($c) use ($abstract,$concrete){
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete);
};


但是
getClosure
返回的是一个闭包,闭包函数不会被立刻调用,所以我们暂时不知道
$c
这个参数是什么,但是我们知道
$abstrac
,
$concrete
分别对应
'tool'
'Train'
这两个字符串

2.然后是第一次
make()

这是第一次调用
make()
,参数的值应该是
'tool'
getConcrete()
会返回之前
bind()
的那个闭包,此处闭包仍然没有被执行。

isBuildable()
返回
true
,于是我们来到第一次
build()
,传入的参数是之前
bind()
的那个闭包,
if ($concrete instanceof Closure)
会返回
true
,于是执行了这一句

return $concrete($this);


闭包终于被执行了,还记得第一步中
bind()
的那几个参数吗,闭包中的

return $c->$method($concrete);


就等效于

return $this->make('Train');


3.之后就是第二次
make()

这次就简单了,
getConcrete()
会返回
'Train'
,
isBuildable()
返回
true
,于是我们来到第二次
build()
,传入的参数是
'Train'


4.使用反射来搞定依赖注入

build()
中可以看到,因为
Train
这个类没有构造函数,所以直接
new
了一个出来并返回,如果
Train
这个类有构造函数,它会根据构造函数中的参数去容器中再次
make()
并注入到
Train
里面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ioc 闭包