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
在线短消息收发的程序,不用数据库
Oct 09 PHP
一个图形显示IP的PHP程序代码
Oct 19 PHP
php 无法载入mysql扩展
Mar 12 PHP
鸡肋的PHP单例模式应用详解
Jun 03 PHP
PHP Cookie的使用教程详解
Jun 03 PHP
PHP中浮点数计算比较及取整不准确的解决方法
Jan 09 PHP
PHP 中 Orientation 属性判断上传图片是否需要旋转
Oct 16 PHP
linux下为php添加iconv模块的方法
Feb 28 PHP
Symfony2函数用法实例分析
Mar 18 PHP
thinkPHP框架自动填充原理与用法分析
Apr 03 PHP
php实现简易计算器
Aug 28 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
晶体管来复再生式二管收音机
2021/03/02 无线电
PHP的引用详解
2015/02/22 PHP
PHP判断是否连接上网络的方法
2015/07/01 PHP
jQuery ajax+PHP实现的级联下拉列表框功能示例
2019/02/12 PHP
自适应高度框架 ----属个人收藏内容
2007/01/22 Javascript
比较简单的一个符合web标准的JS调用flash方法
2007/11/29 Javascript
利用jQuery 实现GridView异步排序、分页的代码
2010/02/06 Javascript
有趣的JavaScript数组长度问题代码说明
2011/01/20 Javascript
js中parseFloat(参数1,参数2)定义和用法及注意事项
2013/01/27 Javascript
关于JavaScript与HTML的交互事件
2013/04/12 Javascript
Javascript 命名空间模式
2013/11/01 Javascript
js截取小数点后几位的写法
2013/11/14 Javascript
js的flv视频播放器插件使用方法
2015/06/23 Javascript
jQuery实现的tab标签切换效果示例
2016/09/05 Javascript
jQuery实现可拖拽的许愿墙效果【附demo源码下载】
2016/09/14 Javascript
详解Vue方法与事件
2017/03/09 Javascript
浅谈Angular 中何时取消订阅
2017/11/22 Javascript
webpack构建的详细流程探底
2018/01/08 Javascript
vue iview实现动态路由和权限验证功能
2018/04/17 Javascript
vue 组件中添加样式不生效的解决方法
2018/07/06 Javascript
vue-router中scrollBehavior的巧妙用法
2018/07/09 Javascript
vue.js 2.*项目环境搭建、运行、打包发布的详细步骤
2019/05/01 Javascript
vue中 v-for循环的用法详解
2020/02/19 Javascript
VUE项目axios请求头更改Content-Type操作
2020/07/24 Javascript
python encode和decode的妙用
2009/09/02 Python
Python微信企业号开发之回调模式接收微信端客户端发送消息及被动返回消息示例
2017/08/21 Python
如何利用Python模拟GitHub登录详解
2019/07/15 Python
python3爬虫中多线程的优势总结
2020/11/24 Python
Boden澳大利亚官网:英国在线服装公司
2018/08/05 全球购物
值传递还是引用传递
2015/02/08 面试题
2016年先进教师个人事迹材料
2016/02/26 职场文书
2016年社会管理综治宣传月活动总结
2016/03/16 职场文书
启迪人心的励志语录:脾气永远不要大于本事
2020/01/02 职场文书
Python中使用ipython的详细教程
2021/06/22 Python
webpack的移动端适配方案小结
2021/07/25 Javascript
Python如何加载模型并查看网络
2022/07/15 Python