关于php:Laravel-反射机制

一、背景
在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)}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理