我的编程空间,编程开发者的网络收藏夹
学习永远不晚

PHP 反射

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

PHP 反射

阅读目录

参考文档

官网:
https://www.php.net/manual/zh/book.reflection.php
https://www.php.net/manual/zh/class.reflection.php
https://www.qycn.com/xzx/article/405.html

Laravel 通过类的反射, 对类的私有属性赋值

TestController 类

namespace App\Http\Controllers\Services;use App\CommentModel;use App\Http\Controllers\Controller;class TestController extends Controller{    public function getList()    {        $data = ["good_id"=>1,"name"=>"商品名"];        $good = $this->ins(TwoTestController::class ,$data);        dd($good);    }        public function ins($class , $data)    {        $classObj = new \ReflectionClass($class);// 反射 TwoTestController 类        $classMethods = $classObj->getMethods(\ReflectionMethod::IS_PUBLIC); // 获取公共方法        $class_instantce = $classObj->newInstance(); // 通过反射对象创建类的实例        foreach ($classMethods as $method){//            echo $method->getName().PHP_EOL; // 获取公共方法的方法名            # 过滤出set开头的公共方法(我这里只有一个setGoodId方法)            if (preg_match("/^set(\w+)/" ,$method->getName() ,$matches)) {//                echo $matches[1].PHP_EOL; // 输出的是GoodId//                echo $this->filterMethod($matches[1]).PHP_EOL; // 输出的是good_id                $this->filterMethod($matches[1] ,$classObj ,$data, $class_instantce);            }        }        return $class_instantce;    }    function filterMethod($name ,\ReflectionClass $classObj ,$data , &$class_instance){        // GoodId 转换成 Good_Id , 左边是小写才添加_ , aGoodId 转换成a_Good_Id        $filter_name =  strtolower(preg_replace("/(?<=[a-z])([A-Z])/","_$1" ,$name));        $props = $classObj->getProperties(\ReflectionProperty::IS_PRIVATE); //获取私有属性        foreach ($props as $prop){            if ($prop->getName() == $filter_name){                $method = $classObj->getMethod("set".$name);                $args = $method->getParameters(); // 获取方法的参数                // 参数数量为1 , 并且数据中存在对应的值                if (count($args)==1 && isset($data[$filter_name])){                    // 反射执行方法                    $method->invoke($class_instance, $data[$filter_name]);                }            }        }    }}

TwoTestController 类

namespace App\Http\Controllers\Services;use Illuminate\Http\Request;use App\Http\Controllers\Controller;class TwoTestController extends Controller{    private $good_id;    private $name;    public function setGoodId($good_id)    {        $this->good_id = $good_id;    }    public function getGoodId()    {        return $this->good_id;    }    public function setName($name)    {        $this->name = $name;    }    public function getName()    {        return $this->name;    }}

预览

在这里插入图片描述

PHP中的反射理解

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

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

与运行时类型信息(Runtime Type Informatiion, RTTI)不同,反射重点在运行时检测、感知、改变自身的结构和行为。

反射是元编程(metaprogramming)的重要组成部分。

PHP反射API均以 Reflection 开头

反射不是语法分析,不操作表达式、代码语句。

反射获取的是代码的结构,即函数、类这些构件的结构。

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<?phpclass 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);PS E:\PDF\test> php .\foo.phpconstruct, instance id: 1object(Foo)#1 (0) {}PS E:\PDF\test>
# ReflectionClass 类报告了一个类的有关信息,建立Foo这个类的反射类$class = new ReflectionClass("Foo");# 获取类的构造函数$constructor = $class->getConstructor();// var_dump(ReflectionProperty::IS_PUBLIC);exit;int(1)// var_dump($constructor->getModifiers());// PS E:\PDF\test> php .\foo.php// int(4)// construct, instance id: 1// object(Foo)#3 (0) {// }// var_dump(ReflectionProperty::IS_PUBLIC & $constructor->getModifiers());exit;//0# ReflectionProperty::IS_PUBLIC,检查属性是否为公共# Gets the property modifiers,获取属性修饰符if ((ReflectionProperty::IS_PUBLIC & $constructor->getModifiers()) === 0) {    # 设置访问控制权:setAccessible 可获取私有的方法/属性。    # 注意:setAccessible 只是让方法/成员变量可以 invoke/getValue/setValue,并不代表类定义的访问存取权限改变;    $constructor->setAccessible(true);}# 创建一个新的类的实例而不调用它的构造函数。$instance2 = $class->newInstanceWithoutConstructor();# ReflectionMethod::invoke()函数是PHP中的内置函数,用于调用指定的反射方法并返回方法的结果。$constructor->invoke($instance2);var_dump($instance2);
# 脚本执行结果construct, instance id: 1object(Foo)#1 (0) {}construct, instance id: 2object(Foo)#4 (0) {}

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

反射API和函数式API在功能上的差异

功能函数式API反射API
函数是否存在function_existsReflectionFunction
类是否存在class_exitsReflectionClass
方法是否存在method_exitsReflectionMethod
变量/属性是否存在property_exitsReflectionProperty
获取类变量get_class_varsReflectionClass::getProperties
获取类方法get_class_methodsReflectionClass::getMethods
获取类常量ReflectionClass::RegetReflectionConstant(s)
获取函数/方法参数信息ReflectionFunction/Method::getParameters
获取函数/方法返回值ReflectionFunction/Method::getReturnType
类使用的特性class_usesReflectionClass::getTraits
获取父类class_parentsReflectionClass::getParentClass
获取类实现的接口class_implementsReflectionClass::getInterfaceNames
获取类所在名字空间__NAMESPACE__ReflectionClass::getNamespaceName
函数调用call_user_func(_array)ReflectionMethod(Function)::invoke(Args)
获取类名__CLASS__/::classReflectionClass::getName
获取函数名__METHOD__/__FUNCTION__ReflectionFunction/Method::getName
获取类/常量/变量/方法修饰符ReflectionClass/Constant/Property/Method::getModifiers
获取所在文件__FILE__ReflectionClass/Constant/Function/Method::getFileName
获取所在行(范围)ReflectionClass/Function/Method::getStartLine/getEndLine
获取文档ReflectionClass/Function/Method::getDocComment
extension_loadedReflectionZendExtension
拓展get_loaded_extensionsReflectionExtension
get_extension_funcs

函数式API和反射API在功能上的差异

功能函数式API反射API
类型判断is_int/is_bool/is_array等
获取对象的类名get_classReflectionObject::getName
获取对象父类get_parent_classReflectionObject::getParentClass
类型/继承检测instanceof/is_a/is_subclass_ofReflectionObject::isInstance/isSubclassOf
生成器ReflectionGenerator

php 反射类 ReflectionClass

class fuc{    //定义一个类    public static function ec()    {        echo'我是一个类';    }}$class = new ReflectionClass('fuc'); //建立 fuc这个类的反射类echo $class; //输出这反射类//相当于实例化 fuc 类$fuc=$class->newInstance();  //执行 fuc 里的方法ec$fuc->ec(); 
PS E:\PDF\test> php .\foo.phpClass [ <user> class fuc ] {  @@ E:\PDF\test\foo.php 3-11  - Constants [0] {  }  - Static properties [0] {  }  - Static methods [1] {    Method [ <user> static public method ec ] {      @@ E:\PDF\test\foo.php 6 - 9    }  }  - Properties [0] {  }  - Methods [0] {  }}我是一个类PS E:\PDF\test>

示例1

class Person {        public  $datang = '123';    public  $datang1 = '1234';     private function getName(){        echo  $this->datang;    }     public function getName1(){        echo $this->datang1;    } } //建立 Person这个类的反射类$class = new ReflectionClass('Person'); //打印所有属性名,包含private,protected,public$properties = $class->getProperties();foreach ($properties as $key => $value) {    var_dump($value->getName());}//打印所有属性的注释并正则,包含private,protected,publicforeach($properties as $property) {    $docblock = $property->getDocComment();    //只能打印多行注释    var_dump($docblock);    preg_match('/ type\=([a-z_]*) /', $docblock, $matches);    var_dump($matches);} //打印所有方法名foreach ($class->getMethods() as $key => $value) {    var_dump($value->getName());} //相当于实例化Person 类$instance  = $class->newInstanceArgs();//执行getName1方法,方法必须是public属性的,否则会报fatal error$instance->getName1(); //获取Person getName1方法$ec=$class->getmethod('getName1');//执行getName1方法,方法必须是public属性的,否则会报fatal error$ec->invoke($instance);

简单的学习反射

class Reflectionstudy{        private $name;        public static function ref1()    {        $ref   = new ReflectionClass('Redis'); //获得Redis的一个反射实例        $const = $ref->getConstants(); //返回所有常量名和值        echo "----------consts---" . PHP_EOL;        array_walk($const, function ($val, $key) {            echo $key, ':', $val, PHP_EOL;        });        $props = $ref->getDefaultProperties(); //返回类中所有属性        echo "----------props---" . PHP_EOL;        array_walk($props, function ($val, $key) {            echo $key, ':', $val, PHP_EOL;        });        $methods = $ref->getMethods(); //返回类中所有方法        echo "----------methods---" . PHP_EOL;        array_walk($methods, function ($val) {            echo $val, PHP_EOL;        });        //当想获取具体的方案有哪些参数时,我们需要进一步反射        echo "----------params---" . PHP_EOL;        echo $ref->getMethod('bitpos'); //传入方法名,会调用$reflectMetho    d->__tostring() 返回可打印的数组    }        public function getName()    {        return self::$name;    }    public function setName($v)    {        self::$name = $v;    }}

1、用户获取对象相关信息 ReflectionObject

$ro = new ReflectionObject(new Reflectionstudy);print_r($ro->getMethods());
PS E:\PDF\test> php .\foo.phpArray(    [0] => ReflectionMethod Object        (            [name] => ref1            [class] => Reflectionstudy        )    [1] => ReflectionMethod Object        (            [name] => getName            [class] => Reflectionstudy        )    [2] => ReflectionMethod Object        (            [name] => setName            [class] => Reflectionstudy        ))PS E:\PDF\test>

2、反射某个方法以及注释信息

$rm = new ReflectionMethod('Reflectionstudy','getName');echo $rm->isPublic(),PHP_EOL;//确认方法是否公有,返回BOOL值echo $rm->getDocComment(),PHP_EOL;//返回文档注释
PS E:\PDF\test> php .\foo.php1PS E:\PDF\test>

3、ReflectionParameter获取函数或方法参数的相关信息

$p = new ReflectionParameter(['Reflectionstudy','setName'],0);echo $p->getPosition(),PHP_EOL;//0,从左向右获得参数,以0开始echo $p->getName(),PHP_EOL;//v
PS E:\PDF\test> php .\foo.php0vPS E:\PDF\test>

4、获取类内属性注释

$p = new ReflectionProperty('Reflectionstudy','name');echo $p->getDocComment(),PHP_EOL;//获取类内属性注释
PS E:\PDF\test> php .\foo.phpPS E:\PDF\test>

5、反射类大致内容

//反射类大致内容Reflectionstudy::ref1();

反射的机制直接将 private 方法设置成外部可访问

class Foo {  private function myPrivateMethod() {    return 7;  }}$method = new ReflectionMethod('Foo', 'myPrivateMethod');//该反射功能直接将原本是private权限的方法设置成可访问$method->setAccessible(true);echo $method->invoke(new Foo);// echos "7"

来源地址:https://blog.csdn.net/weiguang102/article/details/127535021

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

PHP 反射

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

2023-09-02

php有反射吗

这篇文章主要讲解了“php有反射吗”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“php有反射吗”吧!php有反射,php具有完整的反射API,增加了内省类、接口、函数、方法和扩展的能力; 此
2023-06-22

php 有没有反射

php有反射,php具有完整的反射API,增加了内省类、接口、函数、方法和扩展的能力; 此外,反射API提供了方法来取出函数、类和方法中的文档注释。
2020-08-08

Unity3d 射线反射

As any person that has already used Unity’s Ray class knows, there’s no support for reflection, which could be useful fo
2023-01-31

PHP反射指的是什么

这篇“PHP反射指的是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“PHP反射指的是什么”文章吧。反射,直观理解就是根据
2023-07-05

Python_反射

一.反射定义放射是指程序可以访问。检测和修改它本身状态或行为的一种能力(自省)。二.四个自省的函数Python中提供了以下四种自省的函数,使用于类和对象。1.hasattr函数--用于判断obj中有没有name字符串对应的方法或属性,若有返
2023-01-31

PHP的反射机制是什么

本篇内容主要讲解“PHP的反射机制是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PHP的反射机制是什么”吧!简介就算是类成员定义为private也可以在外部访问,不用创建类的实例也可以访问
2023-06-20

AS3反射

反射这玩意,在一些游戏的框架中的确有其优势,但是注意反射或多或少会影响性能的.在资源的获取上就 使用了反射 , 得到SWF中的美术的资源 如:public static function getClazz(className : Strin
2023-01-31

php反射类ReflectionClass用法分析

ReflectionClass是PHP中的一个内置类,用于获取和操作类的反射信息。通过ReflectionClass,我们可以获取类的属性、方法、常量等信息,并且可以对类进行实例化和调用方法。ReflectionClass的基本用法如下:1
2023-08-08

python 反射

1.反射主要是用到了4个函数(  用的最多的就是getattr()和 hasattr()  ):getattr()   从xxx对象中获取到xxx属性值hasattr()  判断xxx对象中是否有xxx属性值delattr()   从xxx
2023-01-30

Python-----反射

class Person(object): """定义一个人类""" def __init__(self, name): self.name = name def eat(self, food):
2023-01-31

Python27 反射

反射:通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法1.getattr:2.hasattr:判断一个对象里是否有对应(相同名称)字符串的方法3.setattr4.delattrclass Dog(object):
2023-01-31

Python反射

反射的定义根据字符串的形式去某个对象中操作成员根据字符串的形式去一个对象中寻找成员根据字符串的形式去一个对象中设置成员根据字符串的形式去一个对象中删除成员根据字符串的形式去一个对象中判断成员是否存在初始反射通过字符串的形式,导入模块根据用户
2023-01-31

PHP中如何使用反射机制?

反射机制允许php程序在运行时检查和修改自身结构,包括获取类型信息、调用方法、设置属性等。通过使用reflection类,开发者可以创建反射对象,并使用is()、get()、invoke()和setvalue()方法来获取信息、调用方法和设
PHP中如何使用反射机制?
2024-05-21

Python 反射-isinstance

用到的isinstance(对象,类)  -------------------  判断一个对象是否是一个类的实例issubclass(子类,父类)  ----------------  判断一个类是否是一个类的子类hasattr(对象,字
2023-01-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录