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+MYSQL开发工具及资源收藏
Jan 02 PHP
php安全配置 如何配置使其更安全
Dec 16 PHP
利用php获取服务器时间的实现代码
Jun 07 PHP
探讨:如何使用PHP实现计算两个日期间隔的年、月、周、日数
Jun 13 PHP
PHP中的类型约束介绍
May 11 PHP
ThinkPHP路由详解
Jul 27 PHP
Laravel中注册Facades的步骤详解
Mar 16 PHP
PHP使用FFmpeg获取视频播放总时长与码率等信息
Sep 13 PHP
php使用PDO事务配合表格读取大量数据插入操作实现方法
Feb 16 PHP
详解PHP的抽象类和抽象方法以及接口总结
Mar 15 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
Aug 13 PHP
解决PHP使用CURL发送GET请求时传递参数的问题
Oct 11 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执行Curl时报错提示CURL ERROR: Recv failure: Connection reset by peer的解决方法
2014/06/26 PHP
微信公众平台接口开发入门示例
2014/12/24 PHP
PHP5.2下preg_replace函数的问题
2015/05/08 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
JQuery 简便实现页面元素数据验证功能
2007/03/24 Javascript
由document.body和document.documentElement想到的
2009/04/13 Javascript
JavaScript 自动完成脚本整理(33个)
2009/10/20 Javascript
javascript截取字符串(通过substring实现并支持中英文混合)
2013/06/24 Javascript
在JS中如何调用JSP中的变量
2014/01/22 Javascript
微信小程序 HTTPS报错整理常见问题及解决方案
2016/12/14 Javascript
jquery UI Datepicker时间控件冲突问题解决
2016/12/16 Javascript
javascript中call,apply,bind函数用法示例
2016/12/19 Javascript
最基础的vue.js双向绑定操作
2017/08/23 Javascript
vue中遇到的坑之变化检测问题(数组相关)
2017/10/13 Javascript
微信小程序使用input组件实现密码框功能【附源码下载】
2017/12/11 Javascript
vue项目中应用ueditor自定义上传按钮功能
2018/04/27 Javascript
浅谈Vue.js路由管理器 Vue Router
2018/08/16 Javascript
教你如何编写Vue.js的单元测试的方法
2018/10/17 Javascript
vue 本地服务不能被外部IP访问的完美解决方法
2018/10/29 Javascript
js打开word文档预览操作示例【不是下载】
2019/05/23 Javascript
微信小程序实现电子签名功能
2020/07/29 Javascript
Python实现windows下模拟按键和鼠标点击的方法
2015/03/13 Python
Python简单删除目录下文件以及文件夹的方法
2015/05/27 Python
python获取array中指定元素的示例
2019/11/26 Python
tornado+celery的简单使用详解
2019/12/21 Python
Trina Turk官网:美国时装和泳装品牌
2018/06/10 全球购物
乌克兰数字设备、配件和智能技术的连锁商店:KTC
2020/08/18 全球购物
医科大学生的自我评价
2013/12/04 职场文书
秋季运动会加油稿200字
2014/01/11 职场文书
采购人员的个人自我评价
2014/01/16 职场文书
模具专业毕业生自荐书范文
2014/02/19 职场文书
商务考察邀请函模板
2015/02/02 职场文书
关于教师节的广播稿
2015/08/19 职场文书
《半截蜡烛》教学反思
2016/02/19 职场文书
python​格式化字符串
2022/04/20 Python