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 相关文章推荐
Ajax+PHP 边学边练 之二 实例
Nov 24 PHP
用C/C++扩展你的PHP 为你的php增加功能
Sep 06 PHP
PHP实现克鲁斯卡尔算法实例解析
Aug 22 PHP
PHP使用PHPExcel删除Excel单元格指定列的方法
Jul 06 PHP
php实现批量修改文件名称的方法
Jul 23 PHP
ThinkPHP3.2.1图片验证码实现方法
Aug 19 PHP
PHP实现原生态图片上传封装类方法
Nov 08 PHP
Yii2下session跨域名共存的解决方案
Feb 04 PHP
yii2使用gridView实现下拉列表筛选数据
Apr 10 PHP
phpStudy配置多站点多域名和多端口的方法
Sep 01 PHP
Laravel事件监听器用法实例分析
Mar 12 PHP
mongodb和php的用法详解
Mar 25 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
php adodb连接带密码access数据库实例,测试成功
2008/05/14 PHP
浅析十款PHP开发框架的对比
2013/07/05 PHP
迅速确定php多维数组的深度的方法
2014/01/07 PHP
PHP学习笔记之php文件操作
2016/06/03 PHP
PHP+MySql实现一个简单的留言板
2020/07/19 PHP
IE、FF、Chrome浏览器中的JS差异介绍
2013/08/13 Javascript
javascript动态添加、修改、删除对象的属性与方法详解
2014/01/27 Javascript
JavaScript更改字符串的大小写
2015/05/07 Javascript
JavaScript获取当前cpu使用率的方法
2015/12/15 Javascript
jQuery+css实现的时钟效果(兼容各浏览器)
2016/01/27 Javascript
浅谈jquery页面初始化的4种方式
2016/11/27 Javascript
JavaScript callback回调函数用法实例分析
2018/05/08 Javascript
vue将毫秒数转化为正常日期格式的实例
2018/09/16 Javascript
jquery的$().each和$.each的区别
2019/01/18 jQuery
JS数组reduce()方法原理及使用技巧解析
2020/07/14 Javascript
[05:03]显微镜下的DOTA2第十期——Ti3豪之超神幽鬼
2014/06/23 DOTA
python+pandas生成指定日期和重采样的方法
2018/04/11 Python
ubuntu 16.04下python版本切换的方法
2019/06/14 Python
Django ImageFiled上传照片并显示的方法
2019/07/28 Python
Python 实现自动导入缺失的库
2019/10/29 Python
Python sep参数使用方法详解
2020/02/12 Python
pyinstaller打包找不到文件的问题解决
2020/04/15 Python
python实现自动清理重复文件
2020/08/24 Python
递归计算如下递归函数的值(斐波拉契)
2012/02/04 面试题
30年同学聚会邀请函
2014/01/25 职场文书
12月红领巾广播稿
2014/02/13 职场文书
高三励志标语
2014/06/05 职场文书
工伤事故赔偿协议书范文
2014/09/24 职场文书
店面出租协议书范本
2014/11/28 职场文书
2014年干部培训工作总结
2014/12/17 职场文书
安全检查汇报材料
2014/12/26 职场文书
安全保证书
2015/01/16 职场文书
2015年健康教育工作总结
2015/04/10 职场文书
三严三实·严以修身心得体会
2016/01/15 职场文书
2016大学生暑期三下乡心得体会
2016/01/23 职场文书
Python使用Beautiful Soup(BS4)库解析HTML和XML
2022/06/05 Python