interface Visit{
public function go();
}
class Train implements Visit{
public function go()
{
echo "go to Tibet by train";
}
}
class Traveller{
protected $trafficTool;
public function __construct(Visit $trafficTool)
{
$this->trafficTool = $trafficTool;
}
public function visitTibet(){
$this->trafficTool->go();
}
}
class Container{
public $bindings = [];public function bind($abstract, $concrete = null, $shared = false){
if(!$concrete instanceof Closure){
//如果不是回调函数,则产生默认的回调
$concrete = $this->getClosure($abstract, $concrete);
}
//将回调函数注册到数组中
$this->bindings[$abstract] = compact('concrete', 'shared');
}
//默认生成实例的回调函数
public function getClosure($abstract, $concrete){
//即build函数中的$concrete($this)。中实现调用
return function ($c) use ($abstract, $concrete){
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete);
};
}
//生成实例对象,首先要解决接口和要实例化类之间的依赖关系,通过make,指定生成注册树上的绑定的类
public function make($abstract){
$concrete = $this->getConcrete($abstract);//获取依赖
if($this->isBuildable($concrete, $abstract)){
$object = $this->build($concrete);
}else{
$object = $this->make($concrete);
}
return $object;
}
public function build($concrete){
if($concrete instanceof Closure){
return $concrete($this);//这个用法不是很清楚
}
//生成反射类
$reflector = new ReflectionClass($concrete);
//判断该类是否能实例化
if (!$reflector->isInstantiable()){
echo $message = '该类不能被实例化';
}
$constructor = $reflector->getConstructor();
//如果没有依赖的类,那么就实例化自身
if(is_null($constructor)){
return new $concrete;
}
$dependencies = $constructor->getParameters();
$instance = $this->getDependencies($dependencies);//获取依赖的对象
return $reflector->newInstanceArgs($instance);//这里实现依赖注入
}
//获取依赖的对象
protected 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;
}
protected function resolveClass(ReflectionParameter $parameter){
return $this->make($parameter->getClass()->name);
}
//获取绑定的回调函数
public function getConcrete($abstract){
if (!isset($this->bindings[$abstract])){
echo '$abstract='.$abstract."</br>";
return $abstract;
}
return $this->bindings[$abstract]['concrete'];
}
public function isBuildable($concrete, $abstract){
return $concrete === $abstract || $concrete instanceof Closure;
}
}
$app = new Container();
$app->bind('Visit','Train');//给Visit接口绑定具体的类
$app->bind('traveller', 'Traveller');
$tra = $app->make('traveller');
$tra->visitTibet();