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中利用XML技术构造远程服务(下)
Oct 09 PHP
?繁体转换的class
Oct 09 PHP
推荐Discuz!5的PHP代码高亮显示与实现可运行代码
Mar 15 PHP
15种PHP Encoder的比较
Apr 17 PHP
生成php程序的php代码
Apr 07 PHP
PHP Mysql编程之高级技巧
Aug 27 PHP
说说PHP的autoLoad自动加载机制
Sep 27 PHP
基于PHP开发中的安全防范知识详解
Jun 06 PHP
thinkphp的CURD和查询方式介绍
Dec 19 PHP
摘自织梦CMS中的图片处理类
Aug 08 PHP
PHP基于方差和标准差计算学生成绩的稳定性示例
Jul 04 PHP
Laravel 默认邮箱登录改成用户名登录的实现方法
Aug 12 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
smarty中post用法实例
2014/11/28 PHP
PHP实现通过get方式识别用户发送邮件的方法
2015/07/16 PHP
php+mysql实现简单登录注册修改密码网页
2016/11/30 PHP
CentOS7编译安装php7.1的教程详解
2019/04/18 PHP
一个对于js this关键字的问题
2007/01/09 Javascript
使用自定义setTimeout和setInterval使之可以传递参数和对象参数
2009/04/24 Javascript
javascript 面向对象全新理练之数据的封装
2009/12/03 Javascript
深入解析Backbone.js框架的依赖库Underscore.js的作用
2016/05/07 Javascript
js基于cookie方式记住返回页面用法示例
2016/05/27 Javascript
jQuery中ScrollTo用法示例
2016/09/04 Javascript
Bootstrap模态框案例解析
2017/03/05 Javascript
vue+jquery+lodash实现滑动时顶部悬浮固定效果
2018/04/28 jQuery
玩转vue的slot内容分发
2018/09/22 Javascript
使用react render props实现倒计时的示例代码
2018/12/06 Javascript
基于Vue全局组件与局部组件的区别说明
2020/08/11 Javascript
Vue.js暴露方法给WebView的使用操作
2020/09/07 Javascript
Vue实现手机号、验证码登录(60s禁用倒计时)
2020/12/19 Vue.js
用Python编写生成树状结构的文件目录的脚本的教程
2015/05/04 Python
Python编程修改MP3文件名称的方法
2017/04/19 Python
python 筛选数据集中列中value长度大于20的数据集方法
2018/06/14 Python
Python SMTP发送邮件遇到的一些问题及解决办法
2018/10/24 Python
关于Python核心框架tornado的异步协程的2种方法详解
2019/08/28 Python
Pycharm连接远程服务器过程图解
2020/04/30 Python
Python轻量级web框架bottle使用方法解析
2020/06/13 Python
matplotlib 画动态图以及plt.ion()和plt.ioff()的使用详解
2021/01/05 Python
CSS3实现菜单悬停效果
2020/11/17 HTML / CSS
Html5移动端网页端适配(js+rem)
2021/02/03 HTML / CSS
JAKO-O德国野酷台湾站:德国首屈一指的婴幼童用品品牌
2019/01/14 全球购物
C#实现对任一张表的数据进行增,删,改,查要求,运用Webservice,体现出三层架构
2014/07/11 面试题
新郎新娘婚礼答谢词
2014/01/11 职场文书
总经理岗位职责范本
2014/02/02 职场文书
高中生学期学习自我评价
2014/02/24 职场文书
安全标兵事迹材料
2014/08/17 职场文书
离婚协议书怎么写的
2014/12/14 职场文书
运动会100米加油稿
2015/07/21 职场文书
Pandas实现DataFrame的简单运算、统计与排序
2022/03/31 Python