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中使用PDF文档功能
Oct 09 PHP
php 中include()与require()的对比
Oct 09 PHP
dede3.1分页文字采集过滤规则详说(图文教程)续四
Apr 03 PHP
基于php常用正则表达式的整理汇总
Jun 08 PHP
PHP解析html类库simple_html_dom的转码bug
May 22 PHP
php禁止某ip或ip地址段访问的方法
Feb 25 PHP
php中PDO方式实现数据库的增删改查
May 17 PHP
php简单实现sql防注入的方法
Apr 22 PHP
PHP常用算法和数据结构示例(必看篇)
Mar 15 PHP
PHP使用SMTP邮件服务器发送邮件示例
Aug 28 PHP
php分享朋友圈的实现代码
Feb 18 PHP
php实现对短信验证码发送次数的限制实例讲解
Mar 04 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 smarty模版引擎中的缓存应用
2009/12/02 PHP
php微信开发之自定义菜单完整流程
2016/10/08 PHP
PHP+redis实现微博的推模型案例分析
2019/07/10 PHP
JS 参数传递的实际应用代码分析
2009/09/13 Javascript
JQuery 学习笔记01 JQuery初接触
2010/05/06 Javascript
用Javascript评估用户输入密码的强度(Knockout版)
2011/11/30 Javascript
jQuery中after()方法用法实例
2014/12/25 Javascript
Javascript常用小技巧汇总
2015/06/24 Javascript
全面解析Bootstrap排版使用方法(文字样式)
2015/11/30 Javascript
Bootstrap模块dropdown实现下拉框响应
2016/05/22 Javascript
jQuery继承extend用法详解
2016/10/10 Javascript
学习vue.js条件渲染
2016/12/03 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
2016/12/05 Javascript
javascript 网页进度条简单实例
2017/02/22 Javascript
微信小程序局部刷新触发整页刷新效果的实现代码
2018/11/21 Javascript
wx-charts 微信小程序图表插件的具体使用
2019/08/18 Javascript
微信小程序之下拉列表实现方法解析(附完整源码)
2019/08/23 Javascript
浅谈Vue组件单元测试究竟测试什么
2020/02/05 Javascript
ant-design-vue中tree增删改的操作方法
2020/11/03 Javascript
使用webpack和rollup打包组件库的方法
2021/02/25 Javascript
[14:36]2014 DOTA2国际邀请赛中国区预选赛5.21 Orenda VS NE
2014/05/22 DOTA
Python函数的周期性执行实现方法
2016/08/13 Python
python 调用c语言函数的方法
2017/09/29 Python
python采集微信公众号文章
2018/12/20 Python
Keras框架中的epoch、bacth、batch size、iteration使用介绍
2020/06/10 Python
PHP如何防止SQL注入
2014/05/03 面试题
思想品德自我鉴定
2013/10/12 职场文书
标准导师推荐信(医学类)
2013/10/28 职场文书
巾帼建功标兵事迹材料
2014/05/11 职场文书
教室标语大全
2014/06/21 职场文书
授权委托书怎么写
2014/09/25 职场文书
安全守法证明
2015/06/23 职场文书
2019新学期家长会工作计划
2019/08/21 职场文书
python之django路由和视图案例教程
2021/07/26 Python
CSS中实现动画效果-附案例
2022/02/28 HTML / CSS
Redis安装使用RedisJSON模块的方法
2022/03/23 Redis