温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

PHP的反射是什么意思

发布时间:2021-08-11 22:34:36 来源:亿速云 阅读:96 作者:chen 栏目:编程语言

本篇内容主要讲解“PHP的反射是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PHP的反射是什么意思”吧!

  反射是什么意思

  从一个简单的例子理解反射:人有五官四肢,但鲜有人清楚人体内部的经脉走向、骨骼构造。如果你修仙顺利,在丹田深处练出元婴,那么就通过元婴透析身体内部的构造。理解内部构造后,还可以让元婴指引体内真气在经脉的流向,早日修成正果。

  如其名,反射是(从镜子里)照出自身。我们写代码,告诉代码怎么运行,事件发生在编译期。代码运行期间,代码如何知道自己的结构以及能力呢?反射机制相当于代码的元婴,使代码能够感知自身结构,并可(部分)改变运行行为。

  与运行时类型信息(Runtime Type Informatiion, RTTI)不同,反射重点在运行时检测、感知、改变自身的结构和行为。反射是元编程(metaprogramming)的重要组成部分。

  反射API

  反射不是语法分析,不操作表达式、代码语句。反射获取的是代码的结构,即函数、类这些构件的结构。PHP中的反射API均以Reflection开头(接口Reflector除外),重点在函数和类两种结构。而函数可以看成类的成员函数(多一个隐式的this参数)或者静态成员函数(public类型),所以了解反射API可从类信息的ReflectionClass开始。

  ReflectionClass提供了以下获取类基本信息的接口:

  getProperties:获取成员变量/属性,返回一个ReflectionProperty数组;ReflectionProperty类中有对属性详细说明的API:是否默认属性(isDefault),是否私有属性(isPrivate)等。同时ReflectionClass还提供获取特定类别属性的API:getDefaultProperties,getStaticProperties;

  getConstants:获取类中定义的常量;

  getMethods:获取类中定义的方法,返回一个ReflectionMethod数组;ReflectionMethod将在下文讲解;

  getInterfaces:获取类实现的接口;

  getParentClass:获取父类的ReflectionClass实例。

  在反射中,类、接口、特性不分家,所以ReflectionClass提供类型判定API:isInterface、isTrait。

  除了以上基本信息,ReflectionClass(包括ReflectionMethod/ReflectionFunction)还提供了一些不可思议的能力:

  getDocComment:获取类的文档注释信息;

  getFilename:获取类定义的文件;

  getStartLine: 获取类定义的起始行号;

  getEndLine: 获取类定义的结束行号;

  getModifiers:获取类定义的修饰符,其意义名字可通过Reflection::getModifierNames得到,例如:abstract,final。

  如果说前述的类结构信息可以通过现有的API获取(method_exits/property_exits等),上面列出的功能基本上只能通过反射API获取(PHP文件中定义的类并且知道定义文件,可以利用token_get_all得到相同结果,但是实现非常复杂)。这些行为发生在运行期间。由此可见反射API在分析类结构信息功能上的强大。

  除了ReflectionClass,ReflectionMethod和ReflectionFunction是另外反射中另外两个重要的类。函数(function)定义在类外部,方法(method)定义在类内部,两者其实同源,在反射API中有共同的父类:ReflectionFunctionAbstract。ReflectionFunctionAbstract有两者的大部分API,并且基本上是最重要的API。其中最值得关注的是其参数信息的API:getParameters。其获取函数的参数信息,返回一个ReflectionParameter数组。结合getParameters和ReflectionParameter,函数(方法)的结构基本上就清晰了。

  API操作

  知道人体构造和体内真气分布,你可以引导真气到手指,练成一阳指、六脉神剑、弹指神通、九阴白骨爪等;也可以让真气汇聚,冲破任督二脉,开辟洞天;还可以逆转全身经脉,练成蛤蟆功…内省的好处可见一斑。

  反射让代码感知自身结构,有什么好处呢?反射API提供了三种在运行时对代码操作的能力:

  设置访问控制权:setAccessible。可获取私有的方法/属性。注意:setAccessible只是让方法/成员变量可以invoke/getValue/setValue,并不代表类定义的访问存取权限改变;

  调用函数/方法:invoke/invokeArgs。配合获取函数参数的API,可以安全的传参和调用函数,call_user_func(_array)的增强版;

  不依赖构造函数生成实例:newInstanceWithoutConstructor。

  以单例来说一下反射API的功能,单例类代码如下:

  # foo.php

  class Foo {

  private static $id;

  private static $instance;

  private function __construct() {

  ++ self::$id;

  fwrite(STDOUT, "construct, instance id: " . self::$id . "\n");

  }

  public static function getSingleton() {

  if (self::$instance === null) {

  self::$instance = new self();

  }

  return self::$instance;

  }

  }

  在Foo类中,构造函数是私有,获取实例只能通过getSingleton方法,并且获取到的是单例。但在反射API加持下,能获取多个实例:

  $instance1 = Foo::getSingleton();

  var_dump($instance1);

  $class = new ReflectionClass("Foo");

  $constructor = $class->getConstructor();

  if ((ReflectionProperty::IS_PUBLIC & $constructor->getModifiers()) === 0) {

  $constructor->setAccessible(true);

  }

  $instance2 = $class->newInstanceWithoutConstructor();

  $constructor->invoke($instance2);

  var_dump($instance2);

  # 脚本执行结果

  construct, instance id: 1

  object(Foo)#1 (0) {

  }

  construct, instance id: 2

  object(Foo)#4 (0) {

  }

  我们成功的生成了两个实例,并调用构造函数完成对象初始化。如果没有反射API,这几乎是不可能完成的工作。

  除了这三种操作,反射API几乎已无在运行时动态改变代码的行为。但作为动态语言,PHP内置了将数据转换成代码执行的能力(例如create_function/eval、动态函数名调用)。而PHP的好基友JavaScript则可以随时在运行时改变任意函数的行为:

  PHP作为最好的语言,理应能做到在运行时动态增减/改变函数定义。这就需要用到另一个PHP核心开发者“Dmitry Zenovich”打造的大杀器:runkit拓展。这部分内容不属于反射,加之本人了解不深,不再详述。

  从上表可以看出反射API较函数式API能提供更全面的信息。还需要注意到__FILE__这类魔术常量是编译期的工作,不是运行时的能力。

到此,相信大家对“PHP的反射是什么意思”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php
AI