共计 1752 个字符,预计需要花费 5 分钟才能阅读完成。
一、背景
在 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)}
正文完