反射

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

反射是指在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. Keras 最新《面向小数据集构建图像分类模型》
  2. 携手中国电信、中国联通,华为正式发布首个5G超级刀片站 A+P 2.0天线商用网络
  3. JBoss 系列八十: jBPM 6 中使用 jbpm-console 创建执行 BPM 流程 - I
  4. 超图iServer服务管理概述
  5. linux ping 端口_教你排除linux中网络故障问题
  6. 前端学习(2915):数据绑定
  7. android keyevent.java,dispatchKeyEvent简单理解
  8. Python3异常-AttributeError: module 'sys' has no attribute 'setdefaultencoding'
  9. Spark 0.9.0启动脚本——sbin/start-slaves.sh
  10. virtualenv -- python虚拟沙盒
  11. scholarscope不显示影响因子_一劳永逸:这两个查看影响因子的插件你安装了吗?...
  12. 微软应用商店错误代码“0x80131500”怎么修复?
  13. xise php一句话木马,渗透利器 | 常见的WebShell管理工具
  14. android 9.0 10.0 Launcher3修改workspace字体颜色
  15. 国务院发展研究中心发布《中国云计算产业发展与应用白皮书》| 附下载
  16. C语言和win32绿色鼠标连点器,带代码(Windows)
  17. 修复鼠标右键没有vscode快捷入口的问题
  18. 工业级静默活体检测开源算法技术解析记录
  19. Unity中的网络编程
  20. 1天熟记----数据库

热门文章

  1. 总结 | 深度学习PyTorch神经网络箱使用
  2. 吴恩达deeplearning.ai新课上线:TensorFlow移动和web端机器学习
  3. 重磅 | 阿里AI labs百万美元年薪聘请两位顶级视觉科学家
  4. 面向小姐姐的编程——JAVA面向对象之继承(一)
  5. 面向小姐姐的编程——JAVA面向对象之封装(二)
  6. mysql en dump_mysqldump 命令总结
  7. SQL Server占用服务器内存过高
  8. USB 3.0、USB 3.1到底什么区别?
  9. java 遍历 likedlist_Java集合02----LinkedList的遍历方式及应用
  10. Java计基础---常用类之StringBuilder类--String、StringBuilder和StringBuffer 的区别