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 - Html Transfer Code
Oct 09 PHP
逆序二维数组插入一元素的php代码
Jun 08 PHP
PHP5各个版本的新功能和新特性总结
Mar 16 PHP
PHP错误Parse error: syntax error, unexpected end of file in test.php on line 12解决方法
Jun 23 PHP
yii2.0之GridView自定义按钮和链接用法
Dec 15 PHP
高质量PHP代码的50个实用技巧必备(上)
Jan 22 PHP
PHP浮点比较大小的方法
Feb 14 PHP
Thinkphp3.2.3整合phpqrcode生成带logo的二维码
Jul 21 PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
Dec 12 PHP
PHP实现负载均衡下的session共用功能
Apr 17 PHP
PHP获取对象属性的三种方法实例分析
Jan 03 PHP
PHP 枚举类型的管理与设计知识点总结
Feb 13 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 图片文件上传实现代码
2010/12/29 PHP
PHP+JS实现大规模数据提交的方法
2015/07/02 PHP
实例讲解PHP表单验证功能
2019/02/15 PHP
AJAX使用了UpdatePanel后无法使用alert弹出脚本
2010/04/02 Javascript
document.getElementById介绍
2011/09/13 Javascript
JavaScript实现表格排序方法
2013/06/14 Javascript
jquery获取URL中参数解决中文乱码问题的两种方法
2013/12/18 Javascript
jQuery+ajax实现动态执行脚本的方法
2015/01/27 Javascript
javascript的函数劫持浅析
2016/09/26 Javascript
Mac下使用charles遇到的问题以及解决办法
2017/01/10 Javascript
使用mpvue搭建一个初始小程序及项目配置方法
2018/12/03 Javascript
js实现ATM机存取款功能
2020/10/27 Javascript
使用Vue.js 和Chart.js制作绚丽多彩的图表
2019/06/15 Javascript
微信小程序通过一个json实现分享朋友圈图片
2019/09/03 Javascript
vue-路由精讲 二级路由和三级路由的作用
2020/08/06 Javascript
Python编写屏幕截图程序方法
2015/02/18 Python
python实现用户登陆邮件通知的方法
2015/07/09 Python
Python通过OpenCV的findContours获取轮廓并切割实例
2018/01/05 Python
Jupyter notebook远程访问服务器的方法
2018/05/24 Python
PyQt5实现暗黑风格的计时器
2019/07/29 Python
python encrypt 实现AES加密的实例详解
2020/02/20 Python
python IDLE添加行号显示教程
2020/04/25 Python
keras实现基于孪生网络的图片相似度计算方式
2020/06/11 Python
Python应用实现处理excel数据过程解析
2020/06/19 Python
解决Pycharm 运行后没有输出的问题
2021/02/05 Python
使用HTML5 Canvas API绘制弧线的教程
2016/03/22 HTML / CSS
英国演唱会订票网站:Ticket Selection
2018/03/27 全球购物
Ben Sherman官方网站:英国男装品牌
2019/10/22 全球购物
优秀大学生推荐信范文
2013/11/28 职场文书
施工工地安全标语
2014/06/07 职场文书
群众路线个人剖析材料及整改措施
2014/11/04 职场文书
2015年生产车间工作总结
2015/04/22 职场文书
纪检部部长竞选稿
2015/11/21 职场文书
ThinkPHP5和ThinkPHP6的区别
2021/03/31 PHP
html form表单基础入门案例讲解
2021/07/21 HTML / CSS
Python初识逻辑与if语句及用法大全
2021/08/07 Python