反射

反射,直观理解就是根据到达地找到出发地和来源。我们可以仅仅通过一个光秃秃对象就能知道它所属的类、拥有哪些方法。

反射是指在PHP运行状态中,扩展分析PHP程序,导出或提出关于类、方法、属性、参数等的详细信息,包括注释。这种动态获取信息以及动态调用对象方法的功能称为反射API。

反射其实不难理解,我们先举个反射示例

<?php
class person{public $name;public $gender;public function say(){echo $this->name," \tis ",$this->gender,"\r\n";}public function set($name, $value) {echo "Setting $name to $value \r\n";$this->$name= $value;}public function get($name) {if(!isset($this->$name)){echo '未设置默认值';$this->$name="正在为你设置默认值2018新年快乐";}return $this->$name;}
}
$student=new person();
$student->name='Tom';
$student->gender='male';
$student->age=24;

以上示例只是简单赋值,实例化,现在,要获取这个student对象的方法和属性列表该怎么做呢?如以下代码所示:

//反射实现
// 获取对象属性列表
$reflect = new ReflectionObject($student);
$props= $reflect->getProperties();
echo'获取对象属性列表'."\n";
foreach ($props as $prop) {print $prop->getName() ."\n";
}
// 获取对象方法列表
echo'获取对象方法列表'."\n";
$m=$reflect->getMethods();
foreach ($m as $prop) {print $prop->getName() ."\n";
}

输出:

获取对象属性列表
name
gender
age
获取对象方法列表
say
set
get

也可以不用反射API,使用class函数,返回对象属性的关联数组以及更多的信息:

// 返回对象属性的关联数组
print_r(get_object_vars($student));// 类属性
print_r(get_class_vars(get_class($student)));
// 返回由类的方法名组成的数组

输出:

Array
([name] => Tom[gender] => male[age] => 24
)
Array
([name] => [gender] =>
)

假如这个对象是从其他页面传过来的,怎么知道它属于哪个类呢?一句代码就可以搞定:

// 获取对象属性列表所属的类
echo get_class($student);//person

反射API的功能显然更强大,甚至能还原这个类的原型,包括方法的访问权限等,如:

// 反射获取类的原型
$obj = new ReflectionClass('person');
$className = $obj->getName();
$Methods = $Properties = array();
foreach($obj->getProperties() as $v)
{$Propertienes[$v->getName()] = $v;
}
foreach($obj->getMethods() as $v) {$Methods[$v->getName()] = $v;
}
echo "class {$className}\n{\n";
is_array($Properties)&&ksort($Properties);
foreach($Properties as $k => $v)
{echo "\t";echo $v->isPublic() ? ' public' : '',$v->isPrivate() ? 'private' : '',$v->isProtected() ? 'protected':'',$v->isStatic() ? 'static' : '';
  echo "\t{$k}\n";
}
echo "\n";
if(is_array($Methods)) ksort($Methods);
foreach($Methods as $k => $v)
{echo "\tfunction {$k}(){}\n";
}
echo "}\n";

输出:

class person
{function get(){}function say(){}function set(){}
}

不仅如此,PHP手册中关于反射API更是有几十个,可以说,反射完整地描述了一个类或者对象的原型。反射不仅可以用于类和对象,还可以用于函数、扩展模块、异常等。

默认情况下,ReflectionClass会获取到所有的属性,private 和 protected的也可以。如果只想获取到private属性,就要额外传个参数:

 $private_properties = $r->getProperties(ReflectionProperty::IS_PRIVATE);

可用参数列表:

  • ReflectionProperty::IS_STATIC
  • ReflectionProperty::IS_PUBLIC
  • ReflectionProperty::IS_PROTECTED
  • ReflectionProperty::IS_PRIVATE

如果要同时获取public 和private 属性,就这样写:

ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED

通过$property->getName()可以得到属性名,通过getDocComment可以得到写给property的注释。我没改下person完整如下:

<?php
class person{/*** type=primary_autoincrement 注释哦*/protected $id = 0;/*** type=varchar length=25 null*/public $name;/*** type=text null*/public $gender;public function say(){echo $this->name," \tis ",$this->gender,"\r\n";}public function set($name, $value) {echo "Setting $name to $value \r\n";$this->$name= $value;}public function get($name) {if(!isset($this->$name)){echo '未设置默认值';$this->$name="正在为你设置默认值2018新年快乐";}return $this->$name;}
}
$student=new person();
$student->name='Tom';
$student->gender='male';
$student->age=24;$class = new ReflectionClass('Person');
$properties = $class->getProperties();
foreach($properties as $property) {if($property->isProtected()) {$docblock = $property->getDocComment();echo $property->getDocComment()."\n";}
}
// 输出:
// _allowDynamicAttributes
// id
// name
// biography

输出:

/*** type=primary_autoincrement 注释哦*/

有点不可思议了吧。竟然连注释都可以取到。

* 获取方法(methods):通过getMethods() 来获取到类的所有methods。返回的是ReflectionMethod对象的数组。

不再演示。

反射有什么作用

反射可以用于文档生成。因此可以用它对文件里的类进行扫描,逐个生成描述文档。

既然反射可以探知类的内部结构,那么是不是可以用它做hook实现插件功能呢?或者是做动态代理呢?

<?php
class mysql {function connect($db) {echo "连接到数据库${db[0]}\r\n";}
}
class sqlproxy {private $target;function construct($tar) {$this->target[]= new $tar();}function call($name, $args) {foreach ($this->target as $obj) {$r = new ReflectionClass($obj);if ($method = $r->getMethod($name)){if ($method->isPublic() && !$method->isAbstract()) {echo "方法前拦截记录LOG\r\n";$method->invoke($obj, $args);echo "方法后拦截\r\n";}}}}
}
$obj = new sqlproxy('mysql');
$obj->connect('member');

在平常开发中,用到反射的地方不多:一个是对对象进行调试,另一个是获取类的信息。在MVC和插件开发中,使用反射很常见,但是反射的消耗也很大,在可以找到替代方案的情况下,就不要滥用。

PHP有Token函数,可以通过这个机制实现一些反射功能。从简单灵活的角度讲,使用已经提供的反射API是可取的。

很多时候,善用反射能保持代码的优雅和简洁,但反射也会破坏类的封装性,因为反射可以使本不应该暴露的方法或属性被强制暴露了出来,这既是优点也是缺点。

转载于:https://www.cnblogs.com/phpper/p/8452520.html

PHP反射原理的实现相关推荐

  1. java反射原理三种,Java反射的原理,作用

    什么是反射,反射原理 java类的执行需要经历以下过程 编译:.java文件编译后生成.class字节码文件 加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时 ...

  2. 【Android架构师java原理详解】二;反射原理及动态代理模式

    前言: 本篇为Android架构师java原理专题二:反射原理及动态代理模式 大公司面试都要求我们有扎实的Java语言基础.而很多Android开发朋友这一块并不是很熟练,甚至半路初级底子很薄,这给我 ...

  3. 假笨说-从一起GC血案谈到反射原理

    概述 公司之前有个大内存系统(70G以上)一直使用CMS GC,不过因为该系统对时间很敏感,偶尔会因为gclocker导致remark特别长(虽然加了-XX:+CMSScavReengeBeforeR ...

  4. java 反射获取属性名和值_面试官这样问我Java反射原理,我刚好都会

    上周我投递出了简历,岗位是java后端开发工程师.这周美团面试官给我进行了面试,面试过程中他问了Java的反射原理.(不得不夸一句,美团的效率真高,上午面完一面,晚上二面马上安排上了.) 无论什么Ja ...

  5. java基础之 反射_Java基础之反射原理与用法详解

    本文实例讲述了Java基础之反射原理与用法.分享给大家供大家参考,具体如下: 1.什么是反射? 反射其实就是动态的加载类,我们在写JDBC的时候加载驱动Class.forName("xxx& ...

  6. 【信号完整性】信号反射原理

    信号反射原理 0 前言 1 参考方向 2 行波的折射与反射 3 几种特殊端接情况分析 0 前言 一般情况下,可以使用行波的概念去分析信号在传输线中的传输过程.线路中均匀性开始遭到破坏的点称为节点,当行 ...

  7. 卡特兰数 默慈金数 默慈金三角形 反射原理

    卡特兰数 公式 递推式: f ( n ) = ∑ f ( i ) ∗ f ( n − i − 1 ) f(n) = ∑f(i) * f(n-i-1) f(n)=∑f(i)∗f(n−i−1) 0 ≤ i ...

  8. 面试官这样问我Java反射原理,我刚好都会

    上周我投递出了简历,岗位是java后端开发工程师.这周美团面试官给我进行了面试,面试过程中他问了Java的反射原理.(不得不夸一句,美团的效率真高,上午面完一面,晚上二面马上安排上了.) 无论什么Ja ...

  9. Java对象的打印_java反射原理制作对象打印工具

    主要运用java反射原理,格式化输出java对象属性值,特别是list 和map. MyTestUtil.java package utils; import java.lang.reflect.Fi ...

  10. ULua反射原理——自我理解,有问题请斧正,谢谢!

    ULua反射原理 旧版本ULua 使用的类 实现方式 现版本的ulua(tolua) 实现方式 wrap:What ,How? What:wrap是什么 How :Wrap使用与生成 How :对于庞 ...

最新文章

  1. sqlserver用sql语句创建链接服务器
  2. cdatabase读取excel第一行数据_“蟒蛇”py对Excel的读取——数据操作用它,老板都得重新认识你...
  3. 关于bitnami redmine 的一些问题
  4. 重装了java然后说找不到路径,Java第三次作业第五题
  5. python ==》 内置函数
  6. linux和windows互传文件 、用户配置文件和密码配置文件 、用户与用户组管理
  7. Flume整合Kafka采集滚动的日志
  8. 关于Exchange管理控制台报“您的权限不足,无法此查看数据”的解决办法
  9. java linux 服务_java项目部署Linux服务器几种启动方式总结经验
  10. python在线包安装mysql_python安装mysql的依赖包mysql-python操作
  11. 【Go学习笔记2】go语言中的基本数据类型和包的介绍(一)
  12. Java虚拟机(十二)——StringTable
  13. leetcode题解70-爬楼梯
  14. 中文名颜色大全,妈妈再也不担心我找不着好颜色了.
  15. React路由管理 —— React Router 总结
  16. 原理 | 分布式链路跟踪组件 SOFATracer 和 Zipkin 模型转换
  17. HTML打开Excel文件
  18. 输入框过滤表情和颜文字
  19. 人工智能ai思维_人工智能系统如何学习创造性思维
  20. HBase 分布式集群搭建手记

热门文章

  1. C++ Primer 第五版 第6章 6.2——函数参数传递习题答案
  2. 推荐系统 | 引用量超过1000的52篇经典论文
  3. 深度学习(二十七)可视化理解卷积神经网络
  4. linux转码软件下载,格式工厂linux版
  5. java中局部内部类_Java内部类详解--成员内部类,局部内部类,匿名内部类,静态内部类...
  6. java静态类如何赋值_Java class对象说明 Java 静态变量声明和赋值说明
  7. android商店账号密码错误,安卓:我失去了我的安卓密钥商店,我该怎么办?
  8. 黑客秘笈-渗透测试实用指南 第三版
  9. 2019年信息安全工程师备考技巧
  10. Android Studio 常用快捷键(超实用!!!)