一、背景
在laravel中,无论是路由,还是privoder都能够实现主动递归实例化。其实现的原理就是用php的反射,PHP相干反射文档:reference
二、文字表述
1、依据classname实例化反射类 new ReflectionClass($classname);
2、取得$classname构造函数(如果$classname有构造函数就获取结构函数参数,如果没有就间接 new $classname获取实例);
3、依据结构函数参数,判断是否为class类型,如果是class类型,持续递归,获取其所属class类型,如果不是class类型,就用返回默认值;
4、依据结构函数参数,获取去参数依赖(dependencies),而后$reflect->newInstanceArgs(dependencies),取得$classname的实例;
三、模仿实现laravel代码
这里只是把外围大略模仿进去,实在的laravel比此代码简单,性能多得多
foo.php
<?phpnamespace ABC;use ABC\F\Baz;include 'F/baz.php';class Bar{}class Foo{ public $bar; public $baz; public function __construct(Bar $bar,Baz $baz){ $this->bar = $bar; $this->baz = $baz; }}
F/baz.php
<?phpnamespace ABC\F;class Baz{}
run.php
<?phpnamespace ABC;include 'foo.php';class Run{ public function build($class){ $reflect = new \ReflectionClass($class); //php反射 //判断$class 这个类是否能实例化,即非abstract、interface if(!$reflect->isInstantiable()){ throw new \Exception('不能实例化'); } //获取类构造函数 $constructor = $reflect->getConstructor(); //如果没有构造函数间接new if(is_null($constructor)){ return new $class; } //获取$class构造函数中的参数 $params = $constructor->getParameters(); //获取参数及其依赖 $dependencies = $this->getDependenes($params); //从给出的参数创立一个$class类实例 return $reflect->newInstanceArgs($dependencies); } public function getDependenes($params){ $dependenes = []; //循环构造函数中的参数 foreach($params as $param){ //取得参数所属类 $dependency = $param->getClass(); //如果参数不是class类型,返回默认值 if(is_null($dependency)){ $dependenes[]= $this->resloveNonClass($param); }else{ //如果参数是class类型,递归build,获取参数实例 $dependenes[] = $this->build($dependency->name); } } return $dependenes; } public function resloveNonClass($param){ if($param->isDefaultValueAvailable()){ return $param->getDefaultValue(); } throw new \Exception('不能没有默认值');//实在的laravel是有相应的解决 }}$class = 'ABC\Foo';$run = new Run();$object = $run->build($class);var_dump($object);//object(Foo){object(ABC/Bar),object(ABC/F/Baz)}