资讯专栏INFORMATION COLUMN

Laravel源码解析之反射的使用

pinecone / 605人阅读

摘要:本章讲解反射类的使用及对反射的使用。各位很清楚,方法用于解析类,所有方法的实现一定是在引用的文件内。致谢感谢你看到这里,本篇文章源码解析靠个人理解。

前言

PHP的反射类与实例化对象作用相反,实例化是调用封装类中的方法、成员,而反射类则是拆封类中的所有方法、成员变量,并包括私有方法等。就如“解刨”一样,我们可以调用任何关键字修饰的方法、成员。当然在正常业务中是建议不使用,比较反射类已经摒弃了封装的概念。

本章讲解反射类的使用及Laravel对反射的使用。

反射

反射类是PHP内部类,无需加载即可使用,你可以通过实例化 ReflectionClass 类去使用它。

方法

这里列举下PHP反射类常用的方法

方法名 注释
ReflectionClass::getConstant 获取定义过的一个常量
ReflectionClass::getConstants 获取一组常量
ReflectionClass::getConstructor 获取类的构造函数
ReflectionClass::getDefaultProperties 获取默认属性
ReflectionClass::getDocComment 获取文档注释
ReflectionClass::getEndLine 获取最后一行的行数
ReflectionClass::getFileName 获取定义类的文件名
ReflectionClass::getInterfaceNames 获取接口(interface)名称
ReflectionClass::getMethods 获取方法的数组
ReflectionClass::getModifiers 获取类的修饰符
ReflectionClass::getName 获取类名
ReflectionClass::getNamespaceName 获取命名空间的名称
ReflectionClass::getParentClass 获取父类

等等等等.... 所有关于类的方法、属性及其继承的父类、实现的接口都可以查询到。
详细文档请参考官网: http://php.net/manual/zh/clas...

栗子
inNamespace());
    var_dump($function->getName());
    var_dump($function->getNamespaceName());
    var_dump($function->getShortName());
    
    $function = new ReflectionClass("ABFoo");
    
    var_dump($function->inNamespace());
    var_dump($function->getName());
    var_dump($function->getNamespaceName());
    var_dump($function->getShortName());
?>

输出结果

bool(false)
string(8) "stdClass"
string(0) ""
string(8) "stdClass"

bool(true)
string(7) "ABFoo"
string(3) "AB"
string(3) "Foo"
Laravel

Laravel在实现服务容器加载时使用了反射类。现在我们开启“解刨”模式

入口文件 index.php
$app = require_once __DIR__."/../bootstrap/app.php";

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client"s browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(IlluminateContractsHttpKernel::class);

$response = $kernel->handle(
    $request = IlluminateHttpRequest::capture()
);

$response->send();

$kernel->terminate($request, $response);

是引用语句发生的下一行调用了make方法。各位很清楚,make方法用于解析类,所有make方法的实现一定是在引用的文件内。

bootstrapapp.php
$app = new IlluminateFoundationApplication(
    realpath(__DIR__."/../")
);

laravel开始加载它的核心类,所有的实现从 IlluminateFoundationApplication 开始。

IlluminateFoundationApplication
public function make($abstract, array $parameters = [])
{
        $abstract = $this->getAlias($abstract);

        if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
            $this->loadDeferredProvider($abstract);
        }

        return parent::make($abstract, $parameters);
}

在核心类中你可能准确的查找到make方法的存在,它加载了服务提供者随后调用了父类的方法make,要知道作为独立的模块 “服务容器”是绝对不能写在核心类的。懂点设计模式的都很清楚。

IlluminateContainerContainer

$api = $this->app->make("HelpSpotAPI",["id"=>1]); 为例来讲解

// 真正的make方法,它直接调用了resolve继续去实现make的功能
// $abstract = "HelpSpotAPI"
public function make($abstract, array $parameters = [])
{
    // $abstract = "HelpSpotAPI"
    return $this->resolve($abstract, $parameters);
}

...

protected function resolve($abstract, $parameters = [])
{
    ...
    // 判断是否可以合理反射
    // $abstract = "HelpSpotAPI"
    if ($this->isBuildable($concrete, $abstract)) {
        // 实例化具体实例 (实际并不是实例化,而是通过反射“解刨”了)
        $object = $this->build($concrete);
    } else {
        $object = $this->make($concrete);
    }
    ...
}

public function build($concrete)
{
        // $concrete = "HelpSpotAPI"
        if ($concrete instanceof Closure) {
            return $concrete($this, $this->getLastParameterOverride());
        }
        // 实例化反射类
        $reflector = new ReflectionClass($concrete);

        // 检查类是否可实例化
        if (! $reflector->isInstantiable()) {
            return $this->notInstantiable($concrete);
        }

        $this->buildStack[] = $concrete;

        // 获取类的构造函数
        $constructor = $reflector->getConstructor();
        
        if (is_null($constructor)) {
            array_pop($this->buildStack);

            return new $concrete;
        }

        $dependencies = $constructor->getParameters();

        $instances = $this->resolveDependencies(
            $dependencies
        );

        array_pop($this->buildStack);
           
        //  从给出的参数创建一个新的类实例。
        return $reflector->newInstanceArgs($instances);
}

可见一个服务容器就加载成功了。

致谢

感谢你看到这里,本篇文章源码解析靠个人理解。如有出入请拍砖。

希望本篇文章可以帮到你。谢谢

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29414.html

相关文章

  • Laravel源码解析路由使用

    摘要:入口启动后,会先加载服务提供者中间件等组件,在查找路由之前因为我们使用的是门面,所以先要查到的实体类。注册第一步当然还是通过服务提供者,因为这是启动的关键,在内加载路由文件。因路由文件中没有命名空间。 showImg(https://segmentfault.com/img/bVbhjvY?w=600&h=296); 前言 我的解析文章并非深层次多领域的解析攻略。但是参考着开发文档看此...

    MartinDai 评论0 收藏0
  • Laravel学习笔记PHP反射(Reflection) (上)

    摘要:说明中经常使用的反射特性来设计代码,本文主要学习的反射特性,来提高写代码时的设计质量。提供一套检测的两个工具包和,类似于探针一样的东西来探测这些一等公民。限于篇幅,下篇再聊下反射。 说明:Laravel中经常使用PHP的反射特性来设计代码,本文主要学习PHP的反射特性,来提高写代码时的设计质量。PHP提供一套检测class, interface, trait, property, me...

    JessYanCoding 评论0 收藏0
  • LaravelLaravel 框架关键技术解析·读书笔记(一)

    摘要:判断是否存在构造函数,不存在直接实例化,存在则通过来获取输入函数,并有相应的方法解决依赖参数问题,实现依赖注入。 Laravel 框架关键技术解析·读书笔记(一) 第一章 入口文件 请求访问的入口文件,主要完成几部分工作,分别是: 自动加载函数的添加 服务器实例化与服务注册 路由加载 请求实例化与路由分发 相应生成与发送 其中,自动加载函数用于包含引用文件,改文件是composer...

    CocoaChina 评论0 收藏0
  • Laravel 依赖注入源码解析

    在 Laravel 的控制器的构造方法或者成员方法,都可以通过类型约束的方式使用依赖注入,如: public function store(Request $request) { //TODO } 这里 $request 参数就使用了类型约束,Request 是类型约束的类型,它是一个类:IlluminateHttpRequest. 本文研究 Laravel 的依赖注入原理,为什么这样定义...

    Donne 评论0 收藏0
  • Laravel核心——Ioc服务容器源码解析(服务器解析

    摘要:而函数作用是加载延迟服务,与容器解析关系不大,我们放在以后再说。在构造之前,服务容器会先把放入中,继而再去解析。利用服务容器解析依赖的参数。 make解析 首先欢迎关注我的博客: www.leoyang90.cn 服务容器对对象的自动解析是服务容器的核心功能,make 函数、build 函数是实例化对象重要的核心,先大致看一下代码: public function make($abst...

    hearaway 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<