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新手上路(六)
Oct 09 PHP
PHP页面间参数传递的四种方法详解
Jun 09 PHP
php页面防重复提交方法总结
Nov 25 PHP
php多维数组去掉重复值示例分享
Mar 02 PHP
ThinkPHP CURD方法之page方法详解
Jun 18 PHP
PHP 实现类似js中alert() 提示框
Mar 18 PHP
form表单传递数组数据、php脚本接收的实例
Feb 09 PHP
php str_replace替换指定次数的方法详解
May 05 PHP
自制PHP框架之设计模式
May 07 PHP
PHP实现验证码校验功能
Nov 16 PHP
PHP实现的mongoDB数据库操作类完整实例
Apr 10 PHP
php提取微信账单的有效信息
Oct 01 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生成静态页面详解
2006/12/05 PHP
Search File Contents PHP 搜索目录文本内容的代码
2010/02/21 PHP
php函数array_merge用法一例(合并同类数组)
2013/02/03 PHP
详解WordPress中调用评论模板和循环输出评论的PHP函数
2016/01/05 PHP
joomla组件开发入门教程
2016/05/04 PHP
php计算给定日期所在周的开始日期和结束日期示例
2017/02/06 PHP
js类中获取外部函数名的方法与代码
2007/09/12 Javascript
js直接编辑当前cookie的脚本
2008/09/14 Javascript
Javascript 中介者模式实例
2009/12/16 Javascript
js实现简单的可切换选项卡效果
2015/04/10 Javascript
解决js图片加载时出现404的问题
2020/11/30 Javascript
JavaScript中的跨浏览器事件操作的基本方法整理
2016/05/20 Javascript
JavaScript-html标题滚动效果的简单实现
2016/09/08 Javascript
js HTML5上传示例代码完整版
2016/10/10 Javascript
详解基于Node.js的微信JS-SDK后端接口实现代码
2017/07/15 Javascript
JS闭包的几种常见形式实例详解
2017/09/16 Javascript
如何用webpack4带你实现一个vue的打包的项目
2018/06/20 Javascript
angular中两种表单的区别(响应式和模板驱动表单)
2018/12/06 Javascript
解决LayUI数据表格复选框不居中显示的问题
2019/09/25 Javascript
Javascript实现鼠标点击冒泡特效
2019/12/24 Javascript
jenkins自动构建发布vue项目的方法步骤
2021/01/04 Vue.js
跟老齐学Python之折腾一下目录
2014/10/24 Python
Python 中Django安装和使用教程详解
2019/07/03 Python
Python性能分析工具Profile使用实例
2019/11/19 Python
python实现批量处理将图片粘贴到另一张图片上并保存
2019/12/12 Python
nginx搭建基于python的web环境的实现步骤
2020/01/03 Python
python3中的logging记录日志实现过程及封装成类的操作
2020/05/12 Python
html5构建触屏网站之touch事件介绍
2013/01/07 HTML / CSS
Cinque网上商店:德国服装品牌
2019/03/17 全球购物
泰国国际航空公司官网:Thai Airways International
2019/12/04 全球购物
教导处工作制度
2014/01/18 职场文书
安全先进班组材料
2014/12/26 职场文书
风雨哈佛路观后感
2015/06/03 职场文书
2015年教师节新闻稿
2015/07/17 职场文书
MySQL中一条update语句是如何执行的
2022/03/16 MySQL
Windows10安装Apache2.4的方法步骤
2022/06/25 Servers