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
如何用phpmyadmin设置mysql数据库用户的权限
Jan 09 PHP
php权重计算方法代码分享
Jan 09 PHP
php通过数组实现多条件查询实现方法(字符串分割)
May 06 PHP
php中filter_input函数用法分析
Nov 15 PHP
PHP调用MySQL存储过程并返回值的方法
Dec 26 PHP
Zend Framework动作助手Json用法实例分析
Mar 05 PHP
php实现购物车功能(以大苹果购物网为例)
Mar 09 PHP
PHP实现的简单对称加密与解密方法实例小结
Aug 28 PHP
详解PHP的抽象类和抽象方法以及接口总结
Mar 15 PHP
PHP设计模式之简单工厂和工厂模式实例分析
Mar 25 PHP
禁止直接访问php文件代码分享
May 05 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&&mysql)二
2006/10/09 PHP
php二维数组转成字符串示例
2014/02/17 PHP
ThinkPHP的截取字符串函数无法显示省略号的解决方法
2014/06/25 PHP
php获得文件大小和文件创建时间的方法
2015/03/13 PHP
Laravel 5框架学习之向视图传送数据
2015/04/08 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
YII框架关联查询操作示例
2019/04/29 PHP
Aster vs KG BO3 第一场2.18
2021/03/10 DOTA
firefo xml 读写实现js代码
2009/06/11 Javascript
javascript 多级checkbox选择效果
2009/08/20 Javascript
Jquery实现三层遍历删除功能代码
2013/04/23 Javascript
再探JavaScript作用域
2014/09/24 Javascript
JavaScript使用setTimeout实现延迟弹出警告框的方法
2015/04/07 Javascript
JS实现生成会变大变小的圆环实例
2015/08/05 Javascript
基于jQuery日历插件制作日历
2016/03/11 Javascript
javascript基本语法
2016/05/31 Javascript
需要牢记的JavaScript基础知识
2016/09/25 Javascript
jQuery通过ajax快速批量提交表单数据
2016/10/25 Javascript
JS简单获取当前日期时间的方法(如:2017-03-29 11:41:10 星期四)
2017/03/29 Javascript
详解webpack打包第三方类库的正确姿势
2018/10/20 Javascript
JavaScript 扩展运算符用法实例小结【基于ES6】
2019/06/17 Javascript
ES6学习笔记之字符串、数组、对象、函数新增知识点实例分析
2020/01/22 Javascript
如何实现js拖拽效果及原理解析
2020/05/08 Javascript
微信小程序对图片进行canvas压缩的方法示例详解
2020/11/12 Javascript
Vue基于localStorage存储信息代码实例
2020/11/16 Javascript
[03:16]DOTA2完美大师赛主赛事首日集锦
2017/11/23 DOTA
Python中二维列表如何获取子区域元素的组成
2017/01/19 Python
Python实现删除文件中含“指定内容”的行示例
2017/06/09 Python
结合OpenCV与TensorFlow进行人脸识别的实现
2019/10/10 Python
python实现广度优先搜索过程解析
2019/10/19 Python
CSS3 @media的基本用法总结
2019/09/10 HTML / CSS
如何启动时不需输入用户名与密码
2014/05/09 面试题
软件设计的目标是什么
2016/12/04 面试题
简单的JAVA编程面试题
2013/03/19 面试题
党员个人年度总结
2015/02/14 职场文书
vue-cropper插件实现图片截取上传组件封装
2021/05/27 Vue.js