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中的数组操作函数整理
Aug 18 PHP
php数组函数序列 之shuffle()和array_rand() 随机函数使用介绍
Oct 29 PHP
几个实用的PHP内置函数使用指南
Nov 27 PHP
PHP环境中Memcache的安装和使用
Nov 05 PHP
WordPress中制作导航菜单的PHP核心方法讲解
Dec 11 PHP
实现PHP框架系列文章(6)mysql数据库方法
Mar 04 PHP
php pdo oracle中文乱码的快速解决方法
May 16 PHP
支付宝服务窗API接口开发php版本
Jul 20 PHP
PHP实现负载均衡的加权轮询方法分析
Aug 22 PHP
PHP7匿名类的用法示例
Apr 05 PHP
PHP进阶学习之Geo的地图定位算法详解
Jun 19 PHP
phpStorm2020 注册码
Sep 17 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 checkbox 取值详细说明
2010/08/19 PHP
一个PHP验证码类代码分享(已封装成类)
2011/07/17 PHP
深入PHP内存相关的功能特性详解
2013/06/08 PHP
PHP伪静态Rewrite设置之APACHE篇
2014/07/30 PHP
wamp安装后自定义配置的方法
2014/08/23 PHP
php 浮点数比较方法详解
2017/05/05 PHP
实现复选框全选/全不选切换
2006/12/23 Javascript
JQuery 图片延迟加载并等比缩放插件
2009/11/09 Javascript
Ajax请求在数据量大的时候出现超时的解决方法
2014/02/27 Javascript
javascipt:filter过滤介绍及使用
2014/09/10 Javascript
jQuery制作简洁的多级联动Select下拉框
2014/12/23 Javascript
js将json格式的对象拼接成复杂的url参数方法
2016/05/25 Javascript
JavaScript来实现打开链接页面的简单实例
2016/06/02 Javascript
(模仿京东用户注册)用JQuery实现简单表单验证,初学者必看
2018/01/08 jQuery
Vue-cli配置打包文件本地使用的教程图解
2018/08/02 Javascript
深入浅析vue中cross-env的使用
2019/09/12 Javascript
关于angular浏览器兼容性问题的解决方案
2020/07/26 Javascript
vue-model实现简易计算器
2020/08/17 Javascript
浅谈Vue static 静态资源路径 和 style问题
2020/11/07 Javascript
js属性对象的hasOwnProperty方法的使用
2021/02/05 Javascript
对python 中class与变量的使用方法详解
2019/06/26 Python
python GUI库图形界面开发之PyQt5信号与槽事件处理机制详细介绍与实例解析
2020/03/08 Python
Django serializer优化类视图的实现示例
2020/07/16 Python
css3和jquery实现的可折叠导航菜单适合放在手机网页的导航菜单
2014/09/02 HTML / CSS
印尼在线精品店:Berrybenka.com
2016/10/22 全球购物
美国电子产品折扣网站:Daily Steals
2017/05/20 全球购物
白酒市场开发计划书
2014/01/09 职场文书
上课打牌的检讨书
2014/02/15 职场文书
人力资源主管的岗位职责
2014/03/15 职场文书
授权委托书格式范文
2014/08/02 职场文书
单位实习工作证明怎么写
2014/11/02 职场文书
2014年建筑工作总结
2014/11/26 职场文书
公司开会通知
2015/04/20 职场文书
长征观后感
2015/06/09 职场文书
关于企业的执行力标语大全
2020/01/06 职场文书
MySQL的InnoDB存储引擎的数据页结构详解
2022/03/03 MySQL