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 相关文章推荐
新版PHP极大的增强功能和性能
Oct 09 PHP
利用PHP动态生成VRML网页
Oct 09 PHP
PHP分页显示制作详细讲解
Dec 05 PHP
获取远程文件大小的php函数
Jan 11 PHP
php处理json时中文问题的解决方法
Apr 12 PHP
PHP封装分页函数实现文本分页和数字分页
Oct 23 PHP
PHP中new static()与new self()的比较
Aug 19 PHP
PHP实现RTX发送消息提醒的实例代码
Jan 03 PHP
php实现统计二进制中1的个数算法示例
Jan 23 PHP
详解PHP发送邮件知识点
May 06 PHP
PHP框架实现WebSocket在线聊天通讯系统
Nov 21 PHP
discuz论坛更换域名,详细文件修改步骤
Dec 09 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获取本地图片文件并生成xml文件输出具体思路
2013/04/27 PHP
PHP中的use关键字及文件的加载详解
2016/11/28 PHP
php+js实现的无刷新下载文件功能示例
2019/08/23 PHP
XP折叠菜单&amp;仿QQ2006菜单
2006/12/16 Javascript
js中自定义方法实现停留几秒sleep
2014/07/11 Javascript
JS在IE下缺少标识符的错误
2014/07/23 Javascript
jquery的总体架构分析及实现示例详解
2014/11/08 Javascript
jquery判断单选按钮radio是否选中的方法
2015/05/05 Javascript
javascript实现支持移动设备画廊
2015/08/24 Javascript
jQuery实现带玻璃流光质感的手风琴特效
2015/11/20 Javascript
JavaScript与HTML的结合方法详解
2015/11/23 Javascript
JS中call/apply、arguments、undefined/null方法详解
2016/02/15 Javascript
详解JavaScript的内置对象
2016/12/07 Javascript
js实现网页的两个input标签内的数值加减(示例代码)
2017/08/15 Javascript
vue2.0之多页面的开发的示例
2018/01/30 Javascript
Javascript的console['']常用输入方法汇总
2018/04/26 Javascript
微信小程序实现弹出菜单动画
2019/06/21 Javascript
基于js实现判断浏览器类型代码实例
2020/07/17 Javascript
[02:50]【扭转乾坤,只此一招】DOTA2永雾林渊版本开启新篇章
2020/12/22 DOTA
详解Python中的相对导入和绝对导入
2017/01/06 Python
Python使用win32 COM实现Excel的写入与保存功能示例
2018/05/03 Python
利用Python半自动化生成Nessus报告的方法
2019/03/19 Python
win7下 python3.6 安装opencv 和 opencv-contrib-python解决 cv2.xfeatures2d.SIFT_create() 的问题
2019/10/24 Python
Tensorflow 实现释放内存
2020/02/03 Python
pyecharts调整图例与各板块的位置间距实例
2020/05/16 Python
使用keras实现densenet和Xception的模型融合
2020/05/23 Python
Keras自定义实现带masking的meanpooling层方式
2020/06/16 Python
python语言实现贪吃蛇游戏
2020/11/13 Python
python元组拆包实现方法
2021/02/28 Python
贝嫂喜欢的婴儿品牌,个性化的婴儿礼物:My 1st Years
2017/11/19 全球购物
伦敦鲜花递送:Flower Station
2021/02/03 全球购物
教师网络培训感言
2014/03/09 职场文书
法院授权委托书范文
2014/08/02 职场文书
自我检讨报告
2015/01/28 职场文书
分析MySQL抛出异常的几种常见解决方式
2021/05/18 MySQL
面试中老生常谈的MySQL问答集锦夯实基础
2022/03/13 MySQL