//ioc
// 交通工具
interface Visit {
public function go ();
}
class Leg implements Visit {
public function go (){
echo 'legs' ;
}
}
class Car implements Visit {
public function go (){
echo 'car' ;
}
}
class Train implements Visit {
public function go (){
echo ' 火车 ' ;
}
}
// 旅游者类使用的佳通工具 ioc 容器
class Container {
public $binding = [];
public function bind ($abstract , $concrete = null , $shared = false ){
if (!$concrete instanceof Closure ){
// 如果产生的不是闭包函数,则产生默认的闭包函数
//$app->bind('Visit','Train');
$concrete = $this ->getClosure ($abstract , $concrete );
}
/*
*
* 将回调 $concrete 闭包绑定到 $this->binding[$abstract]
* */
$this ->binding [$abstract ] = compact ('concrete' ,'shared' );
}
// 默认生成实例的回调函数
public function getClosure ($abstract , $concrete ){
// 生成实例的回调函数, $c 一般为 ioc 容器对象 在调用回调生成实例时调用
// 即 buid 函数中 $concrete($this)
return function ($c ) use ($abstract , $concrete ){
$method = ($abstract === $concrete )?'build' :'make' ;
// 调用的容器的 build 或者是 make 方法生成实例
return $c ->$method ($concrete );
};
}
// 生成实例对象 首先解决接口和要实例化类之间的依赖关系
public function make ($abstract ){
// 获取绑定的闭包函数
$concrete = $this ->getConcrete ($abstract );
// 判断绑定的是不是闭包如果不是判断参数和获取的闭包是不是同一个,如果是同一个则表示需要实例化此对象
if ($this ->isBuildable ($concrete , $abstract )){
$obj = $this ->build ($concrete );
} else {
$obj = $this ->make ($concrete );
}
return $obj ;
}
// 判断绑定的回调是否和传进来的是否相同
public function isBuildable ($concrete , $abstract ){
return $concrete === $abstract || $concrete instanceof Closure ;
}
// 获取绑定的闭包函数,如果没有绑定则返回参数
public function getConcrete ($abstract ){
if ( !isset ($this ->binding [$abstract ])){
return $abstract ;
}
return $this ->binding [$abstract ]['concrete' ];
}
// 实例化对象
public function build ($concrete ){
if ($concrete instanceof Closure ){
// 返回执行回调并把当前容器穿进去
return $concrete ($this );
}
// 开始实例化此对象
$reflector = new ReflectionClass ($concrete );
// 如果此对象不能实例化报错
if (!$reflector ->isInstantiable ()){
echo 'target $concrete is not instantiable' ;
}
// 获取对象的构造函数
$constructor = $reflector ->getConstructor ();
// 如果对象没有构造函数则返回此对象
if (is_null ($constructor )){
return new $concrete ;
}
// 获取构造函数的参数此类是 reflectionParameter 对象构成的数组
$dependencies = $constructor ->getParameters ();
// 获取依赖的类
$instances = $this ->getDependencies ($dependencies );
// 创建一个新的类实例并把 获取到的依赖类的实例穿进去
return $reflector ->newInstanceArgs ($instances );
}
// 通过反射机制通过实例化对象的依赖
public function getDependencies ($parameters ){
$dependencies = [];
//$parameters 是 ReflectionParameter 类组成的数组
foreach ($parameters as $parameter ){
// 获取参数类型(类就是一种类型);
$dependency = $parameter ->getClass ();
if (is_null ($dependency )){
$dependencies [] = null ;
}else {
// 获取已经注册的工具类实例
$dependencies [] = $this ->resolveClass ($parameter );
}
}
return (array) $dependencies ;
}
public function resolveClass (ReflectionParameter $parameter ){
// 获取参数类名
return $this ->make ($parameter ->getClass ()->name );
}
}
class Traveller {
public $trafficTool ;
public function __construct (Visit $trafficTool )
{
$this ->trafficTool = $trafficTool ;
}
public function visitTibet (){
$this ->trafficTool ->go ();
}
}
$app = new Container ();
// 完成容器的填充
//$app->bind('Visit',function(){
// return new Train();
//});
$app ->bind ('Visit' ,'Train' );
//$app->bind('Visit','Car');
$app ->bind ('traveller' ,'Traveller' );
//print_r($app->binding);
//print_r($app->binding);
// 通过容器实现依赖注入,完成类的实例化
$tra = $app ->make ('traveller' );
$tra ->visitTibet ();