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自定义函数返回多个值
Nov 26 PHP
让PHP更快的提供文件下载的代码
Jun 13 PHP
PHP编码规范的深入探讨
Jun 06 PHP
kohana框架上传文件验证规则写法示例
Jul 14 PHP
PHP实现的简单日历类
Nov 29 PHP
php实现ip白名单黑名单功能
Mar 12 PHP
php实现插入排序
Mar 29 PHP
PHP中header用法小结
May 23 PHP
PHP面向对象程序设计高级特性详解(接口,继承,抽象类,析构,克隆等)
Dec 02 PHP
php rsa 加密,解密,签名,验签详解
Dec 06 PHP
ThinkPHP下表单令牌错误与解决方法分析
May 20 PHP
详解PHP防止直接访问.php 文件的实现方法
Jul 28 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 正确解码javascript中通过escape编码后的字符
2010/01/28 PHP
php通过文件头检测文件类型通用代码类(zip,rar等)
2010/10/19 PHP
php中fgetcsv()函数用法实例
2014/11/28 PHP
php通过修改header强制图片下载的方法
2015/03/24 PHP
php实现mysql数据库分表分段备份
2015/06/18 PHP
PHP中header函数的用法及其注意事项详解
2016/06/13 PHP
PHP is_array() 检测变量是否是数组的实现方法
2016/06/13 PHP
功能强大的php分页函数
2016/07/20 PHP
textarea中的手动换行处理的jquery代码
2011/02/26 Javascript
各浏览器中querySelector和querySelectorAll的实现差异分析
2012/05/23 Javascript
javascript 系统文件夹文件操作及参数介绍
2013/01/08 Javascript
基于JQuery实现的Select级联
2014/01/27 Javascript
jquery过滤特殊字符',防sql注入的实现方法
2016/08/17 Javascript
AngularJS中的DOM操作用法分析
2016/11/04 Javascript
JS组件系列之JS组件封装过程详解
2017/04/28 Javascript
页面间固定参数,通过cookie传值的实现方法
2017/05/31 Javascript
node的process以及child_process模块学习笔记
2018/03/06 Javascript
Vue中JS动画与Velocity.js的结合使用
2019/02/13 Javascript
基于js实现逐步显示文字输出代码实例
2020/04/02 Javascript
vue el-upload上传文件的示例代码
2020/12/21 Vue.js
[48:18]DOTA2-DPC中国联赛 正赛 RNG vs Dynasty BO3 第二场 1月29日
2021/03/11 DOTA
python轻松查到删除自己的微信好友
2016/01/10 Python
Python判断两个对象相等的原理
2017/12/12 Python
深入解析python中的实例方法、类方法和静态方法
2019/03/11 Python
对PyQt5的输入对话框使用(QInputDialog)详解
2019/06/25 Python
CSS3中使用RGBa来调节透明度的教程
2016/05/09 HTML / CSS
html5利用canvas实现颜色容差抠图功能
2019/12/23 HTML / CSS
挪威太阳镜和眼镜网上商城:SmartBuyGlasses挪威
2016/08/20 全球购物
Diamondback自行车:拥有你的冒险
2019/04/22 全球购物
Wiggle澳大利亚:自行车、跑步、游泳商店
2020/11/07 全球购物
实习鉴定范文
2013/12/19 职场文书
出纳担保书范文
2014/04/02 职场文书
2015羊年春节慰问信
2015/02/14 职场文书
男方婚前保证书
2015/02/28 职场文书
关爱留守儿童捐款倡议书
2015/04/27 职场文书
MySQL中B树索引和B+树索引的区别详解
2022/03/03 MySQL