一、背景
在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
<?php
namespace 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
<?php
namespace ABC\F;
class Baz{
}
run.php
<?php
namespace 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)}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。