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开发框架总结收藏
Apr 24 PHP
浅谈php扩展imagick
Jun 02 PHP
destoon实现商铺管理主页设置增加新菜单的方法
Jun 26 PHP
php 在线导入mysql大数据程序
Jun 11 PHP
PHP时间类完整实例(非常实用)
Dec 25 PHP
WordPress后台中实现图片上传功能的实例讲解
Jan 11 PHP
详解PHP的Laravel框架中Eloquent对象关系映射使用
Feb 26 PHP
PHP中file_exists使用中遇到的问题小结
Apr 05 PHP
PHP 在数组中搜索给定的简单实例 array_search 函数
Jun 13 PHP
php 实现一个字符串加密解密的函数实例代码
Nov 01 PHP
PHP常用函数总结(180多个)
Dec 25 PHP
PHP抽象类与接口的区别实例详解
May 09 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/10 日漫
第十五节--Zend引擎的发展
2006/11/16 PHP
如何使用PHP计算上一个月的今天
2013/05/23 PHP
PHP实现数组根据某个单元字段排序操作示例
2018/08/01 PHP
实例讲解PHP表单处理
2019/02/15 PHP
JavaScript获取网页表单action属性的方法
2015/04/02 Javascript
使用JavaScript刷新网页的方法
2015/06/04 Javascript
再谈JavaScript异步编程
2016/01/27 Javascript
js类式继承与原型式继承详解
2016/04/07 Javascript
jQuery实现每隔几条元素增加1条线的方法
2016/06/27 Javascript
jQuery实现图片滑动效果
2017/03/08 Javascript
详解Nodejs之静态资源处理
2017/06/05 NodeJs
vue双花括号的使用方法 附练习题
2017/11/07 Javascript
js 原生判断内容区域是否滚动到底部的实例代码
2017/11/15 Javascript
纯js代码生成可搜索选择下拉列表的实例
2018/01/11 Javascript
详解如何使用webpack打包多页jquery项目
2019/02/01 jQuery
浅谈javascript事件环微任务和宏任务队列原理
2020/09/12 Javascript
JavaScript 判断浏览器是否是IE
2021/02/19 Javascript
[50:58]2018DOTA2亚洲邀请赛3月29日 小组赛A组OpTic VS Newbee
2018/03/30 DOTA
[53:15]Newbee vs Pain 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python实现将一个正整数分解质因数的方法分析
2017/12/14 Python
创建pycharm的自定义python模板方法
2018/05/23 Python
python3实现随机数
2018/06/25 Python
Python3实现的判断回文链表算法示例
2019/03/08 Python
Python pip 安装与使用(安装、更新、删除)
2019/10/06 Python
Python input函数使用实例解析
2019/11/22 Python
pytorch 准备、训练和测试自己的图片数据的方法
2020/01/10 Python
Python Websocket服务端通信的使用示例
2020/02/25 Python
python退出循环的方法
2020/06/18 Python
matplotlib自定义鼠标光标坐标格式的实现
2021/01/08 Python
html svg生成环形进度条的实现方法
2019/09/23 HTML / CSS
汽车检测与维修应届毕业生求职信
2013/10/19 职场文书
节约能源标语
2014/06/17 职场文书
电子专业求职信
2014/06/19 职场文书
十一月早安语录:把心放轻,人生就是一朵自在的云
2019/11/04 职场文书
httpclient调用远程接口的方法
2022/08/14 Java/Android