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 insert语法详解
Jun 07 PHP
PHP jQuery表单,带验证具体实现方法
Feb 15 PHP
PHP独立Session数据库存储操作类分享
Jun 11 PHP
php调用shell的方法
Nov 05 PHP
php编写简单的文章发布程序
Jun 18 PHP
PHP生成随机字符串(3种方法)
Sep 25 PHP
Symfony2安装第三方Bundles实例详解
Feb 04 PHP
PHP 将dataurl转成图片image方法总结
Oct 14 PHP
PHP查找一列有序数组是否包含某值的方法
Feb 07 PHP
TP5框架实现自定义分页样式的方法示例
Apr 05 PHP
PHP手机号码及邮箱正则表达式实例解析
Jul 11 PHP
php框架知识点的整理和补充
Mar 01 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实现paypal整合方法
2010/11/28 PHP
php在线代理转向代码
2012/05/05 PHP
php 在windows下配置虚拟目录的方法介绍
2013/06/26 PHP
linux使用crontab实现PHP执行计划定时任务
2014/05/10 PHP
php字符串的替换,分割和连接方法
2016/05/23 PHP
Symfony2获取web目录绝对路径、相对路径、网址的方法
2016/11/14 PHP
js url传值中文乱码之解决之道
2009/11/20 Javascript
jQuery 常见开发使用技巧总结
2009/12/26 Javascript
JavaScript 判断日期格式是否正确的实现代码
2011/07/04 Javascript
分享一个自定义的console类 让你不再纠结JS中的调试代码的兼容
2012/04/20 Javascript
js中的hasOwnProperty和isPrototypeOf方法使用实例
2014/06/06 Javascript
JavaScript操作HTML DOM节点的基础教程
2016/03/11 Javascript
JavaScript禁止用户多次提交的两种方法
2016/07/24 Javascript
vue bootstrap小例子一枚
2017/06/09 Javascript
浅谈Vue为什么不能检测数组变动
2019/10/14 Javascript
vue+element实现动态加载表单
2020/12/13 Vue.js
python登录豆瓣并发帖的方法
2015/07/08 Python
python获取list下标及其值的简单方法
2016/09/12 Python
Python解析excel文件存入sqlite数据库的方法
2016/11/15 Python
Python基于回溯法子集树模板实现8皇后问题
2017/09/01 Python
Python pickle模块实现对象序列化
2019/11/22 Python
在python3中实现查找数组中最接近与某值的元素操作
2020/02/29 Python
PyCharm MySQL可视化Database配置过程图解
2020/06/09 Python
使用SimpleITK读取和保存NIfTI/DICOM文件实例
2020/07/01 Python
Web时代变迁及html5与html4的区别
2016/01/06 HTML / CSS
HTML5实现音频和视频嵌入的方法
2018/08/22 HTML / CSS
AE美国鹰美国官方网站:American Eagle Outfitters
2016/08/22 全球购物
会计专业毕业生自我评价
2013/09/25 职场文书
工作室成员个人发展规划范文
2014/01/24 职场文书
乡村文明行动实施方案
2014/03/29 职场文书
物流管理专业自荐信
2014/06/23 职场文书
品牌转让协议书
2014/08/20 职场文书
读群众路线的心得体会
2014/09/03 职场文书
2015迎新晚会开场白
2015/07/17 职场文书
2016教师读书思廉心得体会
2016/01/23 职场文书
spring cloud 配置中心native配置方式
2021/09/25 Java/Android