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 相关文章推荐
FCKeditor添加自定义按钮
Mar 27 PHP
PHP类的静态(static)方法和静态(static)变量使用介绍
Feb 19 PHP
PHP在线生成二维码代码(google api)
Jun 03 PHP
使用php显示搜索引擎来的关键词
Feb 13 PHP
php获取本周星期一具体日期的方法
Apr 20 PHP
PHP实现删除字符串中任何字符的函数
Aug 11 PHP
非常全面的php日期时间运算汇总
Nov 04 PHP
在Thinkphp中使用ajax实现无刷新分页的方法
Oct 25 PHP
PHP文件上传、客户端和服务器端加限制、抓取错误信息、完整步骤解析
Jan 12 PHP
删除PHP数组中头部、尾部、任意元素的实现代码
Apr 10 PHP
php链式操作的实现方式分析
Aug 12 PHP
Laravel框架Eloquent ORM修改数据操作示例
Dec 03 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/02 国漫
php简单获取目录列表的方法
2015/03/24 PHP
PHP调用微博接口实现微博登录的方法示例
2018/09/22 PHP
广告切换效果(缓动切换)
2009/05/27 Javascript
JavaScript 继承机制的实现(待续)
2010/05/18 Javascript
使用jQuery+HttpHandler+xml模拟一个三级联动的例子
2011/08/09 Javascript
js中更短的 Array 类型转换
2011/10/30 Javascript
基于JavaScript实现继承机制之构造函数+原型链混合方式的使用详解
2013/05/07 Javascript
DOM基础教程之事件对象
2015/01/20 Javascript
angularJS结合canvas画图例子
2015/02/09 Javascript
标准的js无缝滚动效果
2016/08/30 Javascript
微信小程序开发之实现自定义Toast弹框
2017/06/08 Javascript
浅谈angular4.0中路由传递参数、获取参数最nice的写法
2018/03/12 Javascript
element-ui中select组件绑定值改变,触发change事件方法
2018/08/24 Javascript
原生JS与JQ获取元素的区别详解
2020/02/13 Javascript
vue3.0中友好使用antdv示例详解
2021/01/05 Vue.js
[12:36]《DOTA2》国服注册与激活指南全攻略
2013/04/28 DOTA
[01:18:31]DOTA2-DPC中国联赛定级赛 LBZS vs Magma BO3第一场 1月10日
2021/03/11 DOTA
跟老齐学Python之不要红头文件(2)
2014/09/28 Python
python中使用正则表达式的后向搜索肯定模式(推荐)
2017/11/11 Python
python数据结构之线性表的顺序存储结构
2018/09/28 Python
python实现的自动发送消息功能详解
2019/08/15 Python
python中如何实现将数据分成训练集与测试集的方法
2019/09/13 Python
TensorFlow加载模型时出错的解决方式
2020/02/06 Python
python如何写出表白程序
2020/06/01 Python
Python logging模块异步线程写日志实现过程解析
2020/06/30 Python
芬兰设计商店美国:Finnish Design Shop US
2019/03/25 全球购物
Harrods英国:世界领先的奢侈品百货商店
2020/09/23 全球购物
教师岗位职责
2013/11/17 职场文书
大学生关于奋斗的演讲稿
2014/01/09 职场文书
学校招生宣传广告词
2014/03/19 职场文书
公司合并协议书范本
2014/09/30 职场文书
党的群众路线教育实践活动个人整改措施范文
2014/11/04 职场文书
利用Python多线程实现图片下载器
2022/03/25 Python
使用kubeadm命令行工具创建kubernetes集群
2022/03/31 Servers