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 相关文章推荐
一个改进的UBB类
Oct 09 PHP
php 操作调试的方法
Jul 12 PHP
基于session_unset与session_destroy的区别详解
Jun 03 PHP
php实现上传图片生成缩略图示例
Apr 13 PHP
destoon公司主页模板风格的添加方法
Jun 20 PHP
PHP中soap的用法实例
Oct 24 PHP
PHP中使用imagick实现把PDF转成图片
Jan 26 PHP
利用PHP将图片转换成base64编码的实现方法
Sep 13 PHP
php reset() 函数指针指向数组中的第一个元素并输出实例代码
Nov 21 PHP
php判断str字符串是否是xml格式数据的方法示例
Jul 26 PHP
PHP设计模式之抽象工厂模式实例分析
Mar 25 PHP
PHP实现15位身份证号转18位的方法分析
Oct 16 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 类自动载入的方法
2015/06/03 PHP
高质量PHP代码的50个实用技巧必备(下)
2016/01/22 PHP
ThinkPHP3.2.2实现持久登录(记住我)功能的方法
2016/05/16 PHP
PHP 以POST方式提交XML、获取XML,解析XML详解及实例
2016/10/26 PHP
PHP中如何使用Redis接管文件存储Session详解
2018/11/28 PHP
javascript 鼠标滚轮事件
2009/04/09 Javascript
jQuery使用load()方法载入另外一个网页文件内的指定标签内容到div标签的方法
2015/03/25 Javascript
JS实现仿QQ聊天窗口抖动特效
2015/05/10 Javascript
D3.js实现饼状图的方法详解
2016/09/21 Javascript
jQuery如何跳转到另一个网页 就这么简单
2016/12/28 Javascript
微信小程序 天气预报开发实例代码源码
2017/01/20 Javascript
Angular在模板驱动表单中自定义校验器的方法
2017/08/09 Javascript
JS排序算法之冒泡排序,选择排序与插入排序实例分析
2017/12/13 Javascript
vue中实现methods一个方法调用另外一个方法
2018/02/08 Javascript
JS中的回调函数实例浅析
2018/03/21 Javascript
基于vue实现一个神奇的动态按钮效果
2019/05/15 Javascript
简单了解Javscript中兄弟ifream的方法调用
2019/06/17 Javascript
VSCode Vue开发推荐插件和VSCode快捷键(小结)
2020/08/08 Javascript
如何在 Vue 表单中处理图片
2021/01/26 Vue.js
Python安装Imaging报错:The _imaging C module is not installed问题解决方法
2014/08/22 Python
零基础写python爬虫之使用urllib2组件抓取网页内容
2014/11/04 Python
Python编程实现微信企业号文本消息推送功能示例
2017/08/21 Python
对numpy中array和asarray的区别详解
2018/04/17 Python
浅析Python数据处理
2018/05/02 Python
python把转列表为集合的方法
2019/06/28 Python
在Python中构建增广矩阵的实现方法
2019/07/01 Python
如何理解python中数字列表
2020/05/29 Python
基于keras中的回调函数用法说明
2020/06/17 Python
如何对python的字典进行排序
2020/06/19 Python
什么是serialVersionUID
2016/03/04 面试题
教师试用期自我鉴定
2014/02/12 职场文书
小学关爱留守儿童活动方案
2014/08/25 职场文书
西湖英语导游词
2015/02/06 职场文书
教师自荐信范文
2015/03/06 职场文书
2016年“七一建党节”广播稿
2015/12/18 职场文书
详解Spring Bean的配置方式与实例化
2022/06/10 Java/Android