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中数据的批量导入(csv文件)
Oct 09 PHP
用IE远程创建Mysql数据库的简易程序
Oct 09 PHP
PHP 5.0对象模型深度探索之类的静态成员
Mar 27 PHP
php printf输出格式使用说明
Dec 05 PHP
延长phpmyadmin登录时间的方法
Feb 06 PHP
PHP 计算代码执行耗时的代码修正网上普遍错误
May 14 PHP
php数组的概述及分类与声明代码演示
Feb 26 PHP
ini_set的用法介绍
Jan 07 PHP
PHP和Mysql中转UTF8编码问题汇总
Oct 10 PHP
PHP使用内置函数file_put_contents写入文件及追加内容的方法
Dec 07 PHP
使用PHP连接数据库_实现用户数据的增删改查的整体操作示例
Sep 01 PHP
PHP安装BCMath扩展的方法
Feb 13 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,ASP.JAVA,JAVA代码格式化工具整理
2010/06/15 PHP
CI框架给视图添加动态数据
2014/12/01 PHP
php通过array_unshift函数添加多个变量到数组前端的方法
2015/03/18 PHP
php截取指定2个字符之间字符串的方法
2015/04/15 PHP
PHP中strpos、strstr和stripos、stristr函数分析
2016/06/11 PHP
基于laravel缓冲cache的用法详解
2019/10/23 PHP
DOM下的节点属性和操作小结
2009/05/14 Javascript
JS 无限级 Select效果实现代码(json格式)
2011/08/30 Javascript
javascript中负数算术右移、逻辑右移的奥秘探索
2013/10/17 Javascript
jquery实现炫酷的叠加层自动切换特效
2015/02/01 Javascript
jQuery标签编辑插件Tagit使用指南
2015/04/21 Javascript
用JavaScript来美化HTML的select标签的下拉列表效果
2015/11/17 Javascript
JS 日期与时间戮相互转化的简单实例
2016/06/22 Javascript
微信小程序开发之实现选项卡(窗口顶部TabBar)页面切换
2016/11/25 Javascript
AngularJS通过ng-route实现基本的路由功能实例详解
2016/12/13 Javascript
JS 实现banner图片轮播效果(鼠标事件)
2017/08/04 Javascript
VUE实现表单元素双向绑定(总结)
2017/08/08 Javascript
Angular中响应式表单的三种更新值方法详析
2017/08/22 Javascript
微信小程序使用wxParse解析html的方法示例
2019/01/17 Javascript
实例详解vue中的$root和$parent
2019/04/29 Javascript
详解ES6 Promise的生命周期和创建
2019/08/18 Javascript
Nuxt默认模板、默认布局和自定义错误页面的实现
2020/05/11 Javascript
javascript实现移动端轮播图
2020/12/09 Javascript
Python中asyncore异步模块的用法及实现httpclient的实例
2016/06/28 Python
python获取当前目录路径和上级路径的实例
2018/04/26 Python
深入了解Python 变量作用域
2020/07/24 Python
html5-websocket基于远程方法调用的数据交互实现
2012/12/04 HTML / CSS
尤妮佳moony海外旗舰店:日本殿堂级纸尿裤品牌
2018/02/23 全球购物
吉列剃须刀美国官网:Gillette美国
2018/07/13 全球购物
雷曼兄弟的五金店:Lehman’s Hardware Store
2019/04/10 全球购物
护士优质服务演讲稿
2014/08/26 职场文书
法人代表证明书格式
2014/10/01 职场文书
给男朋友的道歉短信
2015/05/12 职场文书
陪护人员误工证明
2015/06/24 职场文书
申论不会写怎么办?教您掌握这6点思维和原则
2019/07/17 职场文书
MySQL中in和exists区别详解
2021/06/03 MySQL