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 相关文章推荐
也谈截取首页新闻 - 范例
Oct 09 PHP
PHP新手上路(十三)
Oct 09 PHP
php Notice: Undefined index 错误提示解决方法
Aug 29 PHP
PHP FOR MYSQL 代码生成助手(根据Mysql里的字段自动生成类文件的)
Jul 23 PHP
php function用法如何递归及return和echo区别
Mar 07 PHP
codeigniter中view通过循环显示数组数据的方法
Mar 20 PHP
php中关于socket的系列函数总结
May 18 PHP
ThinkPHP发送邮件示例代码
Oct 08 PHP
关于PHP中字符串与多进制转换函数的实例代码
Nov 03 PHP
php  单例模式详细介绍及实现源码
Nov 05 PHP
thinkPHP框架RBAC实现原理分析
Feb 01 PHP
Yii框架的路由配置方法分析
Sep 09 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.NET的WebService的代码
2011/04/22 PHP
Thinkphp框架开发移动端接口(2)
2016/08/18 PHP
PHP用正则匹配form表单中所有元素的类型和属性值实例代码
2017/02/28 PHP
javaScript对象和属性的创建方法
2007/01/15 Javascript
简体中文转换繁体中文(实现代码)
2013/12/25 Javascript
jquery实现input输入框实时输入触发事件代码
2014/01/28 Javascript
JavaScript 数组some()和filter()的用法及区别
2016/05/20 Javascript
Three.js学习之网格
2016/08/10 Javascript
详解nodejs微信公众号开发——6.自定义菜单
2017/04/13 NodeJs
angular使用post、get向后台传参的问题实例
2017/05/27 Javascript
JS和jQuery通过this获取html标签中的属性值(实例代码)
2017/09/11 jQuery
详解ng-alain动态表单SF表单项设置必填和正则校验
2019/06/11 Javascript
原生js实现随机点餐效果
2019/12/10 Javascript
[01:10:02]IG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
几个提升Python运行效率的方法之间的对比
2015/04/03 Python
Python上传package到Pypi(代码简单)
2016/02/06 Python
Python基于Pymssql模块实现连接SQL Server数据库的方法详解
2017/07/20 Python
python实现批量修改文件名代码
2017/09/10 Python
基于python的多进程共享变量正确打开方式
2018/04/28 Python
tensorflow实现简单逻辑回归
2018/09/07 Python
Python中的枚举类型示例介绍
2019/01/09 Python
python实现大转盘抽奖效果
2019/01/22 Python
解决django后台样式丢失,css资源加载失败的问题
2019/06/11 Python
基于Keras中Conv1D和Conv2D的区别说明
2020/06/19 Python
浅谈python出错时traceback的解读
2020/07/15 Python
Python 多进程、多线程效率对比
2020/11/19 Python
利用CSS3实现炫酷的飞机起飞动画
2016/09/17 HTML / CSS
美国庭院家具购物网站:AlphaMarts
2019/04/10 全球购物
Linux中如何用命令创建目录
2015/01/12 面试题
优秀驾驶员先进事迹材料
2014/05/04 职场文书
优秀少先队工作者事迹材料
2014/05/13 职场文书
英语系毕业生求职信
2014/07/13 职场文书
四风批评与自我批评范文
2014/10/14 职场文书
2015年思想品德教学工作总结
2015/07/22 职场文书
工作感想范文
2015/08/07 职场文书
python3实现常见的排序算法(示例代码)
2021/07/04 Python