本文实例讲述了PHP反射机制原理与用法。分享给大家供大家参考,具体如下:

反射

面向对象编程中对象被赋予了自省的能力,而这个自省的过程就是反射。

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

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

如何使用反射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="正在为你设置默认值";
}
return $this->$name;
}
}
$student=new person();
$student->name='Tom';
$student->gender='male';
$student->age=24;

  

现在,要获取这个student对象的方法和属性列表该怎么做呢?如以下代码所示:

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

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

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

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

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

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

// 反射获取类的原型
$obj = new ReflectionClass('person');
$className = $obj->getName();
$Methods = $Properties = array();
foreach($obj->getProperties() as $v)
{
    $Properties[$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
{
public gender
public name
function get(){}
function set(){}
function say(){}
}

  

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

反射有什么作用

该例实现对于每个频道获取相应的类来执行相应的操作。具体如下:

foreach($this->chs as $ch) {
$className = $this->chsMap[$ch];
if($className) { // 如果是合法的类名
// 获取反射类
$class = new ReflectionClass($className);
// 获取类的方法
$recd = $class->getmethod('exeRecd');
// 生成类的实例
$instance = $class->newInstance($this->qq, $this->ip);
// 执行方法
$result[$ch] = $recd->invoke($instance);
}
}

  

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

既然反射可以探知类的内部结构,那么是不是可以用它做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是可取的。

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

希望本文所述对大家PHP程序设计有所帮助。

关于PHP反射的更多相关文章

  1. 隐私泄露杀手锏 —— Flash 权限反射

    [简版:http://weibo.com/p/1001603881940380956046] 前言 一直以为该风险早已被重视,但最近无意中发现,仍有不少网站存在该缺陷,其中不乏一些常用的邮箱.社交网站 ...

  2. Java学习之反射机制及应用场景

    前言: 最近公司正在进行业务组件化进程,其中的路由实现用到了Java的反射机制,既然用到了就想着好好学习总结一下,其实无论是之前的EventBus 2.x版本还是Retrofit.早期的View注解框 ...

  3. 关于 CSS 反射倒影的研究思考

    原文地址:https://css-tricks.com/state-css-reflections 译者:nzbin 友情提示:由于演示 demo 的兼容性,推荐火狐浏览.该文章篇幅较长,内容庞杂,有 ...

  4. 编写高质量代码:改善Java程序的151个建议(第7章:泛型和反射___建议106~109)

    建议106:动态代理可以使代理模式更加灵活 Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发.我们知道一个静态代理是通过主题角色(Prox ...

  5. 运用Mono.Cecil 反射读取.NET程序集元数据

    CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...

  6. .NET面试题系列[6] - 反射

    反射 - 定义,实例与优化 在面试中,通常会考察反射的定义(操作元数据),可以用反射做什么(获得程序集及其各个部件),反射有什么使用场景(ORM,序列化,反序列化,值类型比较等).如果答得好,还可能会 ...

  7. .NET基础拾遗(4)委托、事件、反射与特性

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  8. C++的性能C#的产能?! - .Net Native 系列五:.Net Native与反射

    此系列系小九的学堂原创翻译,翻译自微软官方开发向导,一共分为六个主题.本文是第五个主题:.Net Native与反射. 向导文链接:<C++的性能C#的产能?! - .Net Native 系列 ...

  9. [源码]Literacy 快速反射读写对象属性,字段

    Literacy 说明 Literacy使用IL指令生成方法委托,性能方面,在调用次数达到一定量的时候比反射高很多 当然,用IL指令生成一个方法也是有时间消耗的,所以在只使用一次或少数几次的情况,不但 ...

  10. SI与EMI(一) - 反射是怎样影响EMI

    Mark为期两天的EMC培训中大概分成四个时间差不多的部分,简单来说分别是SI.PI.回流.屏蔽.而在信号完整性的书籍中,也会把信号完整性分为:1.信号自身传输的问题(反射,损耗):2.信号与信号之间 ...

随机推荐

  1. Working with the NSOperationQueue Class

    Multi-tasking prevents apps from freezing. In most programming languages, achieving this is a bit tr ...

  2. Signing Identities, Missing Private Key, Cannot sign App

    这个问题发生在重新安装系统后,丢失了之前的private key等.所以解决方法就是提示的revoke and request. 到developer center中找到certificate中对应的 ...

  3. eclipse和maven生成web项目的war包的操作方法

    一.eclipse中,在需要打包的项目名上右击,然后把鼠标光标指向弹出框中的“run as”: 二.之后会看到在这个弹出框的右侧会出现一个悬浮窗,如下: 三.在上边的第二个悬浮窗鼠标点击“maven  ...

  4. 精通Hibernate——域对象之间的关系

    在域模型中.类之间存在四种关系 1.关联(Association) 类之间的引用关系,能够有一对一.一对多和多对多,比如customer与order之间就是一对多 public class Order ...

  5. mongoDB 删除某一字段、重新名字段

    批量删除字段: {multi:true}:查询到的所有记录都删除. db.collection_name.update({"target_field":{"$exists ...

  6. mysql left join查询没走索引

    SELECT t0.ID as id, t0.`NAME` as name, t0.PHONE as phone, t0.`CITY_CODE` as cityCode, t0.SHOOTING_TI ...

  7. mysql开发之---使用游标双层嵌套对总表进行拆分为帖子表和回复表

    注意点: (1)进行拆分的总表表名是不同的.所以创建暂时表,把总表的数据先插入暂时表 (2)为了避免最外层游标轮询数据结束时,抛出 not found 退出程序,不会运行关闭游标等兴许操作,定义con ...

  8. 強大的Selector框架

    代码地址如下:http://www.demodashi.com/demo/12648.html 前言 在开发的过程中,我们经常会遇到给view设置背景,什么圆形背景啊,圆角背景啊,点击变色背景啊之类的 ...

  9. PICT工具安装使用

    前言:PICT工具在微软公司出品一款成对组合的命令行生成工具.PICT 可有效地按照两两测试Pairwise的原理,进行测试用例设计.在使用PICT时,需要输入与测试用例相关的所有参数,以达到全面覆盖 ...

  10. logstash5安装并实现mariadb数据写入到elasticsearch

    java环境这里默认安装了 ,一般源码安装,这里就不说了 一.安装logstash 安装logstash可以用yum安装,也可以用源码安装: yum安装: 1.导入GPG: rpm --import ...