PHP反射机制原理与用法详解


Posted in PHP onFebruary 15, 2017

本文实例讲述了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更是有几十个,可以说,反射完整地描述了一个类或者对象的原型。反射不仅可以用于类和对象,还可以用于函数、扩展模块、异常等。

反射有什么作用

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

既然反射可以探知类的内部结构,那么是不是可以用它做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 相关文章推荐
PHP中一个控制字符串输出的函数
Oct 09 PHP
PHP中通过ADO调用Access数据库的方法测试不通过
Dec 31 PHP
php性能优化分析工具XDebug 大型网站调试工具
May 22 PHP
php基础学习之变量的使用
Jun 09 PHP
php实现encode64编码类实例
Mar 24 PHP
手把手编写PHP框架 深入了解MVC运行流程
Sep 19 PHP
php版微信公众账号第三方管理工具开发简明教程
Sep 23 PHP
Laravel实现自定义错误输出内容的方法
Oct 10 PHP
Laravel实现定时任务的示例代码
Aug 10 PHP
windows 2008r2+php5.6.28环境搭建详细过程
Jun 18 PHP
PHP实现限制域名访问的实现代码(本地验证)
Sep 13 PHP
如何使用php生成zip压缩包
Apr 21 PHP
thinkphp Apache配置重启Apache1 restart 出错解决办法
Feb 15 #PHP
php+redis实现注册、删除、编辑、分页、登录、关注等功能示例
Feb 15 #PHP
Yii2 hasOne(), hasMany() 实现三表关联的方法(两种)
Feb 15 #PHP
Yii2中hasOne、hasMany及多对多关联查询的用法详解
Feb 15 #PHP
详解配置 Apache 服务器支持 PHP 文件的解析
Feb 15 #PHP
PHP使用Redis替代文件存储Session的方法
Feb 15 #PHP
Yii2中多表关联查询hasOne hasMany的方法
Feb 15 #PHP
You might like
针对初学PHP者的疑难问答(1)
2006/10/09 PHP
Codeigniter中禁止A Database Error Occurred错误提示的方法
2014/06/12 PHP
yii2实现分页,带搜索的分页功能示例
2017/01/07 PHP
学习YUI.Ext 第六天--关于树TreePanel(Part 1)
2007/03/10 Javascript
formStorage 基于jquery的一个插件(存储表单中元素的状态到本地)
2012/01/20 Javascript
js设置cookie过期及清除浏览器对应名称的cookie
2013/10/24 Javascript
jQuery简单实现banner图片切换
2014/01/02 Javascript
中文输入法不触发onkeyup事件的解决办法
2014/07/09 Javascript
JavaScript中的对象序列化介绍
2014/12/30 Javascript
javascript实现Table排序的方法
2015/05/15 Javascript
javascript作用域链(Scope Chain)用法实例解析
2015/11/30 Javascript
Bootstrap表单Form全面解析
2016/06/13 Javascript
jQuery内容过滤选择器用法示例
2016/09/09 Javascript
基于JavaScript实现类名的添加与移除
2017/04/23 Javascript
node.js操作MongoDB的实例详解
2017/10/11 Javascript
JS实现显示当前日期的实例代码
2018/07/03 Javascript
element-ui tooltip修改背景颜色和箭头颜色的实现
2019/12/16 Javascript
Nodejs + sequelize 实现增删改查操作
2020/11/07 NodeJs
Vue使用Ref跨层级获取组件的步骤
2021/01/25 Vue.js
Python3中类、模块、错误与异常、文件的简易教程
2017/11/20 Python
浅谈Python中函数的定义及其调用方法
2019/07/19 Python
wxPython:python首选的GUI库实例分享
2019/10/05 Python
numpy ndarray 按条件筛选数组,关联筛选的例子
2019/11/26 Python
Python GUI自动化实现绕过验证码登录
2020/01/10 Python
html5 touch事件实现页面上下滑动效果【附代码】
2016/03/10 HTML / CSS
详解快速开发基于 HTML5 网络拓扑图应用
2018/01/08 HTML / CSS
英国潮流网站:END.(全球免邮)
2017/01/16 全球购物
美国最佳选择产品网站:Best Choice Products
2019/05/27 全球购物
四川internet信息高速公路(C#)笔试题
2012/02/29 面试题
如果重写了对象的equals()方法,需要考虑什么
2014/11/02 面试题
低碳生活倡议书
2014/04/14 职场文书
人力资源管理专业自荐信
2014/06/24 职场文书
股东出资证明书(正规版)
2014/09/24 职场文书
田径运动会广播稿
2015/08/19 职场文书
如何把新闻人物写得立体、鲜活?
2019/08/14 职场文书
MySQL系列之二 多实例配置
2021/07/02 MySQL