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支持断点续传的源码
May 16 PHP
Windows 下的 PHP-PEAR 安装方法
Nov 20 PHP
php URL验证正则表达式
Jul 19 PHP
php mssql扩展SQL查询中文字段名解决方法
Oct 15 PHP
php删除与复制文件夹及其文件夹下所有文件的实现代码
Jan 23 PHP
php操作mysql数据库的基本类代码
Feb 25 PHP
PHP pear安装配置教程
May 14 PHP
PHP实现冒泡排序的简单实例
May 26 PHP
PHP面向对象五大原则之单一职责原则(SRP)详解
Apr 04 PHP
如何在Laravel5.8中正确地应用Repository设计模式
Nov 26 PHP
关于PHP5.6+版本“No input file specified”问题的解决
Dec 11 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实现基于微信公众平台开发SDK(demo)扩展的方法
2014/12/22 PHP
php rsa 加密,解密,签名,验签详解
2016/12/06 PHP
PHP计算近1年的所有月份
2017/03/13 PHP
破除网页鼠标右键被禁用的绝招大全
2006/12/27 Javascript
JavaScript使用cookie
2007/02/02 Javascript
jquery全选/全不选/反选另一种实现方法(配合原生js)
2013/04/07 Javascript
JavaScript中的值是按值传递还是按引用传递问题探讨
2015/01/30 Javascript
原生JavaScript编写俄罗斯方块
2015/03/30 Javascript
BootStrap和jQuery相结合实现可编辑表格
2016/04/21 Javascript
JavaScript的MVVM库Vue.js入门学习笔记
2016/05/03 Javascript
Bootstrap缩略图的创建方法
2017/03/22 Javascript
AngulaJS路由 ui-router 传参实例
2017/04/28 Javascript
在vue中封装可复用的组件方法
2018/03/01 Javascript
vue 组件中slot插口的具体用法
2018/04/03 Javascript
Echart折线图手柄触发事件示例详解
2018/12/16 Javascript
VUE脚手架的下载和配置步骤详解
2019/04/01 Javascript
微信小程序实现收货地址左滑删除
2020/11/18 Javascript
javascript canvas API内容整理
2020/02/16 Javascript
在Vue中创建可重用的 Transition的方法
2020/06/02 Javascript
windows如何把已安装的nodejs高版本降级为低版本(图文教程)
2020/12/14 NodeJs
[02:26]DOTA2英雄米拉娜基础教程
2013/11/25 DOTA
[01:00:10]完美世界DOTA2联赛PWL S2 FTD vs Inki 第二场 11.21
2020/11/24 DOTA
python连接MySQL、MongoDB、Redis、memcache等数据库的方法
2013/11/15 Python
python学习入门细节知识点
2018/03/29 Python
PyQT实现多窗口切换
2018/04/20 Python
Python subprocess库的使用详解
2018/10/26 Python
python合并已经存在的sheet数据到新sheet的方法
2018/12/11 Python
python集合删除多种方法详解
2020/02/10 Python
python实现ping命令小程序
2020/12/28 Python
python Scrapy框架原理解析
2021/01/04 Python
Python脚本调试工具安装过程
2021/01/11 Python
解决pytorch 模型复制的一些问题
2021/03/03 Python
全面解析CSS Media媒体查询使用操作(推荐)
2017/08/15 HTML / CSS
电子商务专业推荐信范文
2013/12/02 职场文书
重点工程汇报材料
2014/08/27 职场文书
老公写给老婆的检讨书
2015/05/06 职场文书