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实现水仙花数示例分享
Apr 03 PHP
php使用百度天气接口示例
Apr 22 PHP
php学习笔记之基础知识
Nov 08 PHP
php批量删除cookie的简单实现方法
Jan 26 PHP
php将图片保存为不同尺寸图片的图片类实例
Mar 30 PHP
PHP自带方法验证邮箱是否存在
Feb 01 PHP
轻松掌握php设计模式之访问者模式
Sep 23 PHP
ThinkPHP下表单令牌错误与解决方法分析
May 20 PHP
PHP创建XML的方法示例【基于DOMDocument类及SimpleXMLElement类】
Sep 10 PHP
Laravel修改验证提示信息为中文的示例
Oct 23 PHP
thinkphp框架无限级栏目的排序功能实现方法示例
Mar 29 PHP
php 获取音视频时长,PHP 利用getid3 获取音频文件时长等数据
Apr 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
建立文件交换功能的脚本(一)
2006/10/09 PHP
PHP date函数参数详解
2006/11/27 PHP
经典的PHPer为什么被认为是草根?
2007/04/02 PHP
IIS6+PHP5+MySQL5+Zend Optimizer+phpMyAdmin安装配置图文教程 2009年
2009/06/08 PHP
php面向对象全攻略 (十五) 多态的应用
2009/09/30 PHP
基于PHP的简单采集数据入库程序
2014/07/30 PHP
PHP日期函数date格式化UNIX时间的方法
2015/03/19 PHP
PHP中PDO的事务处理分析
2016/04/07 PHP
PHP中类与对象功能、用法实例解读
2020/03/27 PHP
Web 前端设计模式--Dom重构 提高显示性能
2010/10/22 Javascript
javascript通过class来获取元素实现代码
2013/02/20 Javascript
JavaScript原型链示例分享
2014/01/26 Javascript
JavaScript strike方法入门实例(给字符串加上删除线)
2014/10/17 Javascript
JavaScript Sort 的一个错误用法示例
2015/03/20 Javascript
jQuery制作可自定义大小的拼图游戏
2015/03/30 Javascript
JS判断字符串变量是否含有某个字串的实现方法
2016/06/03 Javascript
JavaScript的变量声明提升问题浅析(Hoisting)
2016/11/30 Javascript
浅谈对Angular中的生命周期钩子的理解
2017/07/31 Javascript
Vue2.0学习之详解Vue 组件及父子组件通信
2017/12/12 Javascript
详解Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
2018/10/12 Javascript
JS常见错误(Error)及处理方案详解
2020/07/02 Javascript
Python程序设计入门(3)数组的使用
2014/06/16 Python
python文字转语音的实例代码分析
2019/11/12 Python
通过实例解析Python调用json模块
2019/12/11 Python
python通过对字典的排序,对json字段进行排序的实例
2020/02/27 Python
Django模板标签中url使用详解(url跳转到指定页面)
2020/03/19 Python
python实现横向拼接图片
2020/03/23 Python
使用django自带的user做外键的方法
2020/11/30 Python
HTML5梦幻之旅——炫丽的流星雨效果实现过程
2013/08/06 HTML / CSS
h5移动端调用支付宝、微信支付的实现
2020/06/08 HTML / CSS
AmazeUI 输入框组的示例代码
2020/08/14 HTML / CSS
大学新生军训感言
2014/02/25 职场文书
外贸业务员求职信
2014/06/16 职场文书
感谢师恩主题班会
2015/08/17 职场文书
MySQL视图概念以及相关应用
2022/04/19 MySQL
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers