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 相关文章推荐
PHP5.0对象模型探索之抽象方法和抽象类
Sep 05 PHP
php 将bmp图片转为jpg等其他任意格式的图片
Jun 29 PHP
解析php常用image图像函数集
Jun 24 PHP
php json与xml序列化/反序列化
Oct 28 PHP
php利用反射实现插件机制的方法
Mar 14 PHP
PHP自定义函数实现格式化秒的方法
Sep 14 PHP
php版微信js-sdk支付接口类用法示例
Oct 12 PHP
php使用Jpgraph创建折线图效果示例
Feb 15 PHP
php将html转为图片的实现方法
May 19 PHP
PHP实现防盗链的方法分析
Jul 25 PHP
PHP使用微信开发模式实现搜索已发送图文及匹配关键字回复的方法
Sep 13 PHP
php 提交表单 关闭layer弹窗iframe的实例讲解
Aug 20 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
2006/12/23 PHP
一个图形显示IP的PHP程序代码
2007/10/19 PHP
支持中文的php加密解密类代码
2011/11/27 PHP
再谈IE中Flash控件的自动激活 ObjectWrap
2007/03/09 Javascript
鼠标选择动态改变网页背景颜色的JS代码
2013/12/10 Javascript
JavaScript验证图片类型(扩展名)的函数分享
2014/05/05 Javascript
使用AngularJS 应用访问 Android 手机的图片库
2015/03/24 Javascript
ECMAScript6中Set/WeakSet详解
2015/06/12 Javascript
javascript 网页进度条简单实例
2017/02/22 Javascript
基于 Vue.js 2.0 酷炫自适应背景视频登录页面实现方式
2018/01/17 Javascript
JS字符串去除连续或全部重复字符的实例
2018/03/08 Javascript
解决Vue+Element ui开发中碰到的IE问题
2018/09/03 Javascript
[46:55]Ti4 冒泡赛第二轮 LGD vs C9
2014/07/14 DOTA
python基于xmlrpc实现二进制文件传输的方法
2015/06/02 Python
python删除列表内容
2015/08/04 Python
python之PyMongo使用总结
2017/05/26 Python
VSCode下好用的Python插件及配置
2018/04/06 Python
Python爬虫包BeautifulSoup学习实例(五)
2018/06/17 Python
Python图像处理之gif动态图的解析与合成操作详解
2018/12/30 Python
python 多进程共享全局变量之Manager()详解
2019/08/15 Python
自定义django admin model表单提交的例子
2019/08/23 Python
python如何通过pyqt5实现进度条
2020/01/20 Python
在python中利用dict转json按输入顺序输出内容方式
2020/02/27 Python
jupyter notebook 多行输出实例
2020/04/09 Python
Nginx+Uwsgi+Django 项目部署到服务器的思路详解
2020/05/08 Python
python设置表格边框的具体方法
2020/07/17 Python
美国一家专业的太阳镜网上零售商:Solstice太阳镜
2016/07/25 全球购物
雅萌 (YA-MAN) :日本美容家电领域的龙头企业
2017/05/12 全球购物
JS原生实现轮播图的几种方法
2021/03/23 Javascript
2014的自我评价
2014/01/13 职场文书
单位成立周年感言
2014/01/26 职场文书
公司捐款倡议书
2014/05/14 职场文书
汽车质检员岗位职责
2015/04/08 职场文书
基石观后感
2015/06/12 职场文书
交通安全主题班会
2015/08/12 职场文书
浅析MySQL如何实现事务隔离
2021/06/26 MySQL