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 相关文章推荐
PHP安装攻略:常见问题解答(二)
Oct 09 PHP
php设计模式 State (状态模式)
Jun 26 PHP
PHP持久连接mysql_pconnect()函数使用介绍
Feb 05 PHP
php更新mysql后获取影响的行数发生异常解决方法
Mar 28 PHP
php 模拟GMAIL,HOTMAIL(MSN),YAHOO,163,126邮箱登录的详细介绍
Jun 18 PHP
PHP-Fcgi下PHP的执行时间设置方法
Aug 02 PHP
PHP判断变量是否为0的方法
Feb 08 PHP
php实现excel中rank函数功能的方法
Jan 20 PHP
PHP使用递归生成文章树
Apr 21 PHP
PHP设计模式之装饰者模式代码实例
May 11 PHP
PHP导出Excel实例讲解
Jan 24 PHP
PHP程序中的文件锁、互斥锁、读写锁使用技巧解析
Mar 21 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数组合并array_merge()函数使用注意事项
2014/06/19 PHP
ThinkPHP 表单自动验证运用示例
2014/10/13 PHP
JQuery写动态树示例代码
2013/07/31 Javascript
iframe子页面获取父页面元素的方法
2013/11/05 Javascript
Jquery中扩展方法extend使用技巧
2014/08/24 Javascript
JS实现进入页面时渐变背景色的方法
2015/02/25 Javascript
angular.fromJson与toJson方法用法示例
2017/05/17 Javascript
AngularJS实现表单验证功能详解
2017/10/12 Javascript
基于vue v-for 循环复选框-默认勾选第一个的实现方法
2018/03/03 Javascript
Vue 实现列表动态添加和删除的两种方法小结
2018/09/07 Javascript
如何使用pm2快速将项目部署到远程服务器
2019/03/12 Javascript
JS实现的自定义map方法示例
2019/05/17 Javascript
vue canvas绘制矩形并解决由clearRec带来的闪屏问题
2019/09/02 Javascript
原生js实现照片墙效果
2020/10/13 Javascript
Python递归遍历列表及输出的实现方法
2015/05/19 Python
Python字典简介以及用法详解
2016/11/15 Python
python dataframe常见操作方法:实现取行、列、切片、统计特征值
2018/06/09 Python
Python实现将Excel转换成xml的方法示例
2018/08/25 Python
python中dict使用方法详解
2019/07/17 Python
Python列表解析操作实例总结
2020/02/26 Python
PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解
2020/04/23 Python
英国广泛的照明产品网站:Lights4living
2018/01/28 全球购物
Sasa莎莎海外旗舰店:香港莎莎美妆平台
2018/03/21 全球购物
教师评优的个人自我评价分享
2013/09/19 职场文书
计算机应用专业学生的自我评价分享
2013/11/03 职场文书
日语专业个人求职信范文
2014/02/02 职场文书
社区网格化管理实施方案
2014/03/21 职场文书
委托书样本
2014/04/02 职场文书
省级优秀班集体申报材料
2014/05/25 职场文书
项目负责人任命书
2014/06/04 职场文书
2016年优秀团支部事迹材料
2016/02/26 职场文书
2016年基层党支部书记公开承诺书
2016/03/25 职场文书
祝福语集锦:给百岁老人祝寿贺词
2019/11/19 职场文书
zabbix监控mysql的实例方法
2021/06/02 MySQL
草系十大最强宝可梦,纸片人上榜,榜首大家最熟悉
2022/03/18 日漫
MySQL数据库之存储过程 procedure
2022/06/16 MySQL