Laravel框架源码解析之反射的使用详解


Posted in PHP onMay 14, 2020

本文实例讲述了Laravel框架源码解析之反射的使用。分享给大家供大家参考,具体如下:

前言

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/class.reflectionclass.php

栗子

<?php
 namespace A\B;
 
 class Foo { }
 
 $function = new \ReflectionClass('stdClass');
 
 var_dump($function->inNamespace());
 var_dump($function->getName());
 var_dump($function->getNamespaceName());
 var_dump($function->getShortName());
 
 $function = new \ReflectionClass('A\\B\\Foo');
 
 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) "A\B\Foo"
string(3) "A\B"
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(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
 $request = Illuminate\Http\Request::capture()
);

$response->send();

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

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

bootstrap\app.php

$app = new Illuminate\Foundation\Application(
 realpath(__DIR__.'/../')
);

laravel开始加载它的核心类,所有的实现从 Illuminate\Foundation\Application 开始。

Illuminate\Foundation\Application

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,要知道作为独立的模块 “服务容器”是绝对不能写在核心类的。懂点设计模式的都很清楚。

Illuminate\Container\Container

$api = $this->app->make('HelpSpot\API',['id'=>1]); 为例来讲解

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

...

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

public function build($concrete)
{
  // $concrete = 'HelpSpot\API'
  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);
}

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

希望本文所述对大家基于Laravel框架的PHP程序设计有所帮助。

PHP 相关文章推荐
Windows PHP5和Apache的安装与配置
Jun 08 PHP
fleaphp常用方法分页之Pager使用方法
Apr 23 PHP
C#使用PHP服务端的Web Service通信实例
Apr 08 PHP
神盾加密解密教程(一)PHP变量可用字符
May 28 PHP
微信公众平台开发实现2048游戏的方法
Apr 15 PHP
PHP实现仿Google分页效果的分页函数
Jul 29 PHP
PHP表单提交后引号前自动加反斜杠的原因及三种办法关闭php魔术引号
Sep 30 PHP
php判断手机浏览还是web浏览,并执行相应的动作简单实例
Jul 28 PHP
PHP基于简单递归函数求一个数阶乘的方法示例
Apr 26 PHP
phpStudy中升级MySQL版本到5.7.17的方法步骤
Aug 03 PHP
PHP PDOStatement::getColumnMeta讲解
Feb 01 PHP
在 Laravel 项目中使用 webpack-encore的方法
Jul 21 PHP
PHP 数组操作详解【遍历、指针、函数等】
May 13 #PHP
ThinkPHP5 框架引入 Go AOP,PHP AOP编程项目详解
May 12 #PHP
php中用unset销毁变量并释放内存
May 10 #PHP
php屏蔽错误及提示的方法
May 10 #PHP
php判断数组是否为空的实例方法
May 10 #PHP
通过PHP实现获取访问用户IP
May 09 #PHP
如何通过PHP实现Des加密算法代码实例
May 09 #PHP
You might like
PHP写的求多项式导数的函数代码
2012/07/04 PHP
codeigniter实现get分页的方法
2015/07/10 PHP
JavaScript多线程的实现方法
2007/05/08 Javascript
Dom在ajax技术中的作用说明
2010/10/25 Javascript
JavaScript学习笔记记录我的旅程
2012/05/23 Javascript
js获取UserControl内容为拼html时提供方便
2014/11/02 Javascript
angularjs实现文字上下无缝滚动特效代码
2016/09/04 Javascript
JS 根据子网掩码,网关计算出所有IP地址范围示例
2020/04/23 Javascript
浅谈js内置对象Math的属性和方法(推荐)
2016/09/19 Javascript
js图片上传的封装代码
2017/08/01 Javascript
理解 Node.js 事件驱动机制的原理
2017/08/16 Javascript
Vue2.0 实现单选互斥的方法
2018/04/13 Javascript
Javascript格式化并高亮xml字符串的方法及注意事项
2018/08/13 Javascript
vue页面切换过渡transition效果
2018/10/08 Javascript
使用Angular Cli如何创建Angular私有库详解
2019/01/30 Javascript
小程序外卖订单界面的示例代码
2019/12/30 Javascript
你准备好迎接vue3.0了吗
2020/04/28 Javascript
python中的__slots__使用示例
2015/02/26 Python
将Django使用的数据库从MySQL迁移到PostgreSQL的教程
2015/04/11 Python
在Python的Flask框架中使用日期和时间的教程
2015/04/21 Python
Python中的数学运算操作符使用进阶
2016/06/20 Python
Python实现代码统计工具(终极篇)
2016/07/04 Python
Python多线程实现同步的四种方式
2017/05/02 Python
python交换两个变量的值方法
2019/01/12 Python
python抓取需要扫微信登陆页面
2019/04/29 Python
python的依赖管理的实现
2019/05/14 Python
pandas DataFrame创建方法的方式
2019/08/02 Python
python安装和pycharm环境搭建设置方法
2020/05/27 Python
python文件及目录操作代码汇总
2020/07/08 Python
周生生珠宝香港官网:Chow Sang Sang(香港及海外配送)
2019/09/05 全球购物
工业自动化毕业生自荐信范文
2014/01/04 职场文书
导游实习生自荐书
2014/01/28 职场文书
迟到检讨书5000字
2014/01/31 职场文书
基于Python绘制子图及子图刻度的变换等的问题
2021/05/23 Python
Python趣味实战之手把手教你实现举牌小人生成器
2021/06/07 Python
解决Oracle数据库用户密码过期
2022/05/11 Oracle