说明
Laravel的核心容器,有一部分就是利用反射来实现依赖注入时类的实例化。这是一个简化版示例。
代码
测试用的类
/** * 坦克标准: 必须能开火 */interface Tank{ public function fire();}/** * 59坦克,使用100毫米炮 */class Tank59 implements Tank{ private $gun = 100; public function fire() { echo $this->gun . PHP_EOL; }}/** * 59加强版,可以使用100毫米炮或120毫米炮,默认120毫米炮 */class Tank59Plus implements Tank{ private $gun; public function __construct($gun = 120) { if($gun != 100 && $gun != 120) { throw new Exception('口径不合适'); } $this->gun = $gun; } public function fire() { echo $this->gun . PHP_EOL; }}/** * 59超级版,可以使用任意口径的炮,必须提供一门火炮 */class Tank59Super implements Tank{ private $gun; public function __construct($gun) { $this->gun = $gun; } public function fire() { echo $this->gun . PHP_EOL; }}/** * 坦克营,装备59和59加强版,必须提供59和59加强版 */class TankArmy implements Tank{ private $tank59; private $tank59Plus; public function __construct(Tank59 $tank59, Tank59Plus $tank59Plus) { $this->tank59 = $tank59; $this->tank59Plus = $tank59Plus; } public function fire() { echo $this->tank59->fire(); echo $this->tank59Plus->fire(); }}
容器
/** * 兵工厂 */class Factory{ /** * 创建实体对象 */ public static function build($blueprint) { //反射,获取类细节 $reflector = new ReflectionClass($blueprint); //无法创建的类,比如接口,抽象类 if(!$reflector->isInstantiable()) { throw new Exception('提供的不是坦克图纸,不能制造'); } //获取类的构造方法 $constructor = $reflector->getConstructor(); if (is_null($constructor)) { //没有构造方法,直接new return new $blueprint; } $parameters = []; //获取构造方法依赖的参数 $dependencies = $constructor->getParameters(); foreach ($dependencies as $dependency) { if(is_null($dependency->getClass())) { //依赖参数不是对象 //如果构造方法参数有默认值,获取默认值 if($dependency->isDefaultValueAvailable()) { $parameters[] = $dependency->getDefaultValue(); } } else { //依赖参数是对象,递归创建 $parameters[] = self::build($dependency->getClass()->name); } } if(!$parameters) { //有构造方法且构造方法有参数,却没有可以提供的实参,无法创建 throw new Exception('坦克缺少必要的零件,不能制造'); } else { //使用反射提供的方法创建对象,传入参数 return $reflector->newInstanceArgs($parameters); } }}
测试
Tank
$tank = Factory::build(Tank::class);echo $tank->fire();//输出//PHP Fatal error: Uncaught Exception: 提供的不是坦克图纸,不能制造
Tank59
$tank = Factory::build(Tank59::class);echo $tank->fire();//输出//100
Tank59Plus
$tank = Factory::build(Tank59Plus::class);echo $tank->fire();//输出//120
Tank59Super
$tank = Factory::build(Tank59Super::class);echo $tank->fire();//输出//Fatal error: Uncaught Exception: 坦克缺少必要的零件,不能制造
TankArmy
$tank = Factory::build(TankArmy::class);echo $tank->fire();//输出//100//120