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 URL编码解码函数代码
Mar 10 PHP
解析PHP汉字转换拼音的类
Jun 18 PHP
php Xdebug的安装与使用详解
Jun 20 PHP
解析在PHP中使用mysqli扩展库对mysql的操作
Jul 03 PHP
PHP中多维数组的foreach遍历示例
Jun 13 PHP
ThinkPHP实现将本地文件打包成zip下载
Jun 26 PHP
php结合js实现点击超链接执行删除确认操作
Oct 31 PHP
PHP+Mysql实现多关键字与多字段生成SQL语句的函数
Nov 05 PHP
php实现excel中rank函数功能的方法
Jan 20 PHP
PHP添加图片水印、压缩、剪切的封装类
Aug 17 PHP
WordPress的主题编写中获取头部模板和底部模板
Dec 28 PHP
PHP四种排序算法实现及效率分析【冒泡排序,插入排序,选择排序和快速排序】
Apr 27 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 运行效率总结(提示程序速度)
2009/11/26 PHP
php数组函数序列之each() - 获取数组当前内部指针所指向元素的键名和键值,并将指针移到下一位
2011/10/31 PHP
PHP比你想象的好得多
2014/11/27 PHP
Linux操作系统安装LAMP环境
2015/06/26 PHP
php结合ajax实现手机发红包的案例
2016/10/13 PHP
微信 开发生成带参数的二维码的实例
2016/11/23 PHP
yii2 上传图片的示例代码
2018/11/02 PHP
Lazy Load 延迟加载图片的 jQuery 插件
2010/02/06 Javascript
与jquery serializeArray()一起使用的函数,主要来方便提交表单
2011/01/31 Javascript
js动态创建、删除表格示例代码
2013/08/07 Javascript
javascript面向对象之共享成员属性与方法及prototype关键字用法
2015/01/13 Javascript
javascript获取select值的方法分析
2015/07/02 Javascript
Angularjs中如何使用filterFilter函数过滤
2016/02/06 Javascript
使用Vue.js创建一个时间跟踪的单页应用
2016/11/28 Javascript
jQuery+HTML5实现WebGL高性能烟花绽放动画效果【附demo源码下载】
2017/08/18 jQuery
js实现把时间戳转换为yyyy-MM-dd hh:mm 格式(es6语法)
2017/12/28 Javascript
JS检索下拉列表框中被选项目的索引号(selectedIndex)
2019/12/17 Javascript
在Python的Django框架中调用方法和处理无效变量
2015/07/15 Python
python3中set(集合)的语法总结分享
2017/03/24 Python
使用Python实现租车计费系统的两种方法
2018/09/29 Python
python 使用正则表达式按照多个空格分割字符的实例
2018/12/20 Python
python3+pyqt5+itchat微信定时发送消息的方法
2019/02/20 Python
pyqt5 实现 下拉菜单 + 打开文件的示例代码
2019/06/20 Python
Python实现一个数组除以一个数的例子
2019/07/20 Python
PYcharm 激活方法(推荐)
2020/03/23 Python
html5应用缓存_动力节点Java学院整理
2017/07/13 HTML / CSS
Born鞋子官网:Born Shoes
2017/04/06 全球购物
澳大利亚UGG工厂直销:Australian Ugg Boots
2017/10/14 全球购物
墨西哥皇宫度假村预订:Palace Resorts
2018/06/16 全球购物
俄罗斯美容和健康网上商店:Созвездие Красоты
2019/07/23 全球购物
Myprotein比利时官方网站:欧洲第一运动营养品牌
2020/10/04 全球购物
什么是三层交换,说说和路由的区别在那里
2014/09/01 面试题
办公室综合文员岗位职责范本
2014/02/13 职场文书
高中语文教材(文学文化常识大全一)
2019/08/13 职场文书
一篇文章带你搞懂Python类的相关知识
2021/05/20 Python
《艾尔登法环》Boss腐烂树灵很有可能是《黑暗之魂3》的一个废案
2022/04/11 其他游戏