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 相关文章推荐
让你的网站首页自动选择语言转跳
Dec 06 PHP
php入门小知识
Mar 24 PHP
PHP 函数学习简单小结
Jul 08 PHP
php代码运行时间查看类代码分享
Aug 06 PHP
用PHP写的基于Memcache的Queue实现代码
Nov 27 PHP
smarty缓存用法分析
Dec 16 PHP
php中实现xml与mysql数据相互转换的方法
Dec 25 PHP
PHP输入流php://input实例讲解
Dec 22 PHP
PHP仿tp实现mvc框架基本设计思路与实现方法分析
May 23 PHP
使用SMB共享来绕过php远程文件包含的限制执行RFI的利用
May 31 PHP
PHP保留两位小数的几种方法
Jul 24 PHP
laravel 获取当前url的别名方法
Oct 11 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 服务器配置(使用Apache及IIS两种方法)
2009/06/01 PHP
基于PHP导出Excel的小经验 完美解决乱码问题
2013/06/10 PHP
php命令行(cli)模式下报require 加载路径错误的解决方法
2015/11/23 PHP
yii2 resetful 授权验证详解
2017/05/18 PHP
Laravel框架中Blade模板的用法示例
2017/08/30 PHP
laravel框架中表单请求类型和CSRF防护实例分析
2019/11/23 PHP
用jscript实现列出安装的软件列表
2007/06/18 Javascript
javascript各浏览器中option元素的表现差异
2011/04/07 Javascript
js 走马灯简单实例
2013/11/21 Javascript
ionic 上拉菜单(ActionSheet)实例代码
2016/06/06 Javascript
window.open不被拦截的简单实现代码(推荐)
2016/08/04 Javascript
Javascript 动态改变imput type属性
2016/11/01 Javascript
JS前端加密算法示例
2016/12/22 Javascript
Javascript面试经典套路reduce函数查重
2017/03/23 Javascript
react native 原生模块桥接的简单说明小结
2019/02/26 Javascript
浏览器事件循环与vue nextTicket的实现
2019/04/16 Javascript
在vue中获取微信支付code及code被占用问题的解决方法
2019/04/16 Javascript
解决在layer.open中使用时间控件laydate失败的问题
2019/09/11 Javascript
Nodejs环境实现socket通信过程解析
2020/07/03 NodeJs
[02:19]DOTA2女子战队FOX视频专访:希望更多美眉一起加入
2013/10/15 DOTA
[45:40]Ti4 冒泡赛第二天NEWBEE vs NaVi 1
2014/07/15 DOTA
Python实现计算最小编辑距离
2016/03/17 Python
Python3实现并发检验代理池地址的方法
2016/09/18 Python
Python 实现一个颜色色值转换的小工具
2016/12/06 Python
django中url映射规则和服务端响应顺序的实现
2020/04/02 Python
使用numpngw和matplotlib生成png动画的示例代码
2021/01/24 Python
CSS3绘制圆角矩形的简单示例
2015/09/28 HTML / CSS
Russell Stover巧克力官方网站:美国领先的精美巧克力制造商
2016/11/27 全球购物
印度领先的眼镜电子商务网站:Lenskart
2019/12/16 全球购物
计算机专业大学生的自我评价
2013/11/14 职场文书
商业房地产广告语
2014/03/13 职场文书
后备干部培训方案
2014/05/22 职场文书
堂吉诃德读书笔记
2015/06/30 职场文书
2015年幼儿园国庆节活动总结
2015/07/30 职场文书
MySQL root密码的重置方法
2021/04/21 MySQL
手把手教你实现PyTorch的MNIST数据集
2021/06/28 Python