PHP反射原理与用法深入分析


Posted in PHP onSeptember 28, 2019

本文实例讲述了PHP反射原理与用法。分享给大家供大家参考,具体如下:

说到反射,实际上包含两个概念:

  • 检视 introspection 判断类、方法是否存在,父子类关系,调用关系等,检视的函数文档
  • 反射 Reflection 获取类里的方法、属性,注释等,反射类的文档

PHP官方文档写得很清晰了,下面我就说一下具体的应用。

1.参数检测

有时候需要在函数里需要判断传入的参数类型是否合法。
这时可以使用is_a、is_subclass_of来检测。或者结合反射,做更多检测。

2.动态调用

在依赖注入中,常见到这种用法,比如Laravel5.5中的Container.php

public function build($concrete)
  {
    // If the concrete type is actually a Closure, we will just execute it and
    // hand back the results of the functions, which allows functions to be
    // used as resolvers for more fine-tuned resolution of these objects.
    if ($concrete instanceof Closure) {
      return $concrete($this, $this->getLastParameterOverride());
    }
    $reflector = new ReflectionClass($concrete);
    // If the type is not instantiable, the developer is attempting to resolve
    // an abstract type such as an Interface of Abstract Class and there is
    // no binding registered for the abstractions so we need to bail out.
    if (! $reflector->isInstantiable()) {
      return $this->notInstantiable($concrete);
    }
    $this->buildStack[] = $concrete;
    $constructor = $reflector->getConstructor();
    // If there are no constructors, that means there are no dependencies then
    // we can just resolve the instances of the objects right away, without
    // resolving any other types or dependencies out of these containers.
    if (is_null($constructor)) {
      array_pop($this->buildStack);
      return new $concrete;
    }
    $dependencies = $constructor->getParameters();
    // Once we have all the constructor's parameters we can create each of the
    // dependency instances and then use the reflection instances to make a
    // new instance of this class, injecting the created dependencies in.
    $instances = $this->resolveDependencies(
      $dependencies
    );
    array_pop($this->buildStack);
    return $reflector->newInstanceArgs($instances);
  }

上述代码先判断是否是闭包,如果是,直接返回。不是则通过new ReflectionClass($concrete);

生成反射类的实例,然后获取这个类的构造函数和参数,进行初始化的过程。

注意

反射里一个比较重要的用法invoke

当已知这个类的时候,可以通过构造ReflectionMethod来直接调用,如:

class HelloWorld {

  public function sayHelloTo($name) {
    return 'Hello ' . $name;
  }

}

$reflectionMethod = new ReflectionMethod('HelloWorld', 'sayHelloTo');
echo $reflectionMethod->invoke(new HelloWorld(), 'Mike');

当不知道这个类时,知道类的对象,可以用ReflectionObject获取ReflectionMethod后调用,如:

class HelloWorld {

  public function sayHelloTo($name) {
    return 'Hello ' . $name;
  }

}

$hello = new HelloWorld();

$refObj = new ReflectionObject($hello);
$refMethod = $refObj->getMethod('sayHelloTo');
echo $refMethod->invoke($hello,'Mike');

调用流程一般就是获取反射类ReflectionClass/反射对象ReflectionObject的实例,然后获取ReflectionMethod后,invoke。

3.获取注释,生成文档

比如PHPDoc

4.注解,增强版的注释,符合一定的规则

比如某些框架的路由,便是通过注解实现的。

5.不要为了反射而反射

PHP是一门动态语言,其实可以直接通过字符串来调用类或函数,如下:

class HelloWorld {
  public function sayHelloTo($name) {
    return 'Hello ' . $name;
  }
}
$hello = 'HelloWorld';
$helloSay = 'sayHelloTo';
$helloIntance = new $hello;
echo $helloIntance->$helloSay('Mike');

那么为什么还需要反射呢?

  • 功能更强大
  • 更安全,防止直接调用没有暴露的内部方法
  • 可维护,直接写字符串是硬编码

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
网络资源
Oct 09 PHP
php 获取百度的热词数据的代码
Feb 18 PHP
php获取用户IPv4或IPv6地址的代码
Nov 15 PHP
(PHP实现)只使用++运算实现加法,减法,乘法,除法
Jun 27 PHP
PHP实现的简单mock json脚本分享
Feb 10 PHP
PHP计算当前坐标3公里内4个角落的最大最小经纬度实例
Feb 26 PHP
Yii框架上传图片用法总结
Mar 28 PHP
PHP处理二进制数据的实现方法
Jun 13 PHP
php 解析xml 的四种方法详细介绍
Oct 26 PHP
PHP设计模式之抽象工厂模式实例分析
Mar 25 PHP
PHP模版引擎原理、定义与用法实例
Mar 29 PHP
php实现的顺序线性表示例
May 04 PHP
Windows服务器中PHP如何安装redis扩展
Sep 27 #PHP
php-fpm超时时间设置request_terminate_timeout资源问题分析
Sep 27 #PHP
thinkPHP+LayUI 流加载实现功能
Sep 27 #PHP
PHP的cookie与session原理及用法详解
Sep 27 #PHP
PHP下载文件函数与用法示例
Sep 27 #PHP
PHP的JSON封装、转变及输出操作示例
Sep 27 #PHP
php面向对象重点知识分享
Sep 27 #PHP
You might like
星际争霸兵种名称对照表
2020/03/04 星际争霸
php 表单数据的获取代码
2009/03/10 PHP
使用php验证复选框有效性的示例
2013/11/13 PHP
php实现mysql封装类示例
2014/05/07 PHP
SESSION存放在数据库用法实例
2015/08/08 PHP
PHP将字符串首字母大小写转换的实例
2017/01/21 PHP
laravel5.2表单验证,并显示错误信息的实例
2019/09/29 PHP
网页的标准,IMG不支持onload标签怎么办
2006/06/29 Javascript
ASP.NET jQuery 实例10 动态修改hyperlink的URL值
2012/02/03 Javascript
jQuery中detach()方法用法实例
2014/12/25 Javascript
Jquery插件easyUi实现表单验证示例
2015/12/15 Javascript
页面向下滚动ajax获取数据的实现方法(兼容手机)
2016/05/24 Javascript
jQuery 3.0中存在问题及解决办法
2016/07/15 Javascript
JavaScript函数绑定用法实例分析
2017/11/14 Javascript
vue-cli2 构建速度优化的实现方法
2019/01/08 Javascript
使用npm命令提示: 'npm' 不是内部或外部命令,也不是可运行的程序的处理方法
2020/05/14 Javascript
使用Pyrex来扩展和加速Python程序的教程
2015/04/13 Python
Python中基本的日期时间处理的学习教程
2015/10/16 Python
LRUCache的实现原理及利用python实现的方法
2017/11/21 Python
机器学习10大经典算法详解
2017/12/07 Python
python基于ID3思想的决策树
2018/01/03 Python
Django框架的中的setting.py文件说明详解
2018/10/15 Python
Python unittest 简单实现参数化的方法
2018/11/30 Python
Django获取该数据的上一条和下一条方法
2019/08/12 Python
Pyinstaller加密打包应用的示例代码
2020/06/11 Python
在Ubuntu中安装并配置Pycharm教程的实现方法
2021/01/06 Python
详解HTML5中的Communication API基本使用方法
2016/01/29 HTML / CSS
Mankind美国/加拿大:英国领先的男士美容护发用品公司
2018/12/05 全球购物
娇韵诗法国官网:Clarins法国
2019/01/29 全球购物
C#中类(class)与结构(struct)的异同
2013/11/03 面试题
下列程序在32位linux或unix中的结果是什么
2015/01/26 面试题
2014最新房贷收入证明范本
2014/09/12 职场文书
2014党员学习《反腐倡廉警示教育读本》思想汇报
2014/09/13 职场文书
小学教师求职信范文
2015/03/20 职场文书
导游词之湖州-太湖
2019/10/11 职场文书
python入门之算法学习
2021/04/22 Python