PHP通过反射动态加载第三方类和获得类源码的实例


Posted in PHP onNovember 27, 2015

使用反射动态加载第三方类

用反射加载第三方类用处在于:
使用XML或其他配文件配置要加载的类,从而和系统源代码分离。
对加载的类进行类检查,是加载的类符合自己定义的结构。

<?php
  abstract class Module {  #核心Module类库
    function baseFunc() {
      echo "I am baseFunc";
    }
    
    abstract function execute();
  }
  
  class ModuleRunner {
    private $configData = array(  #模拟xml配置,动态配置需要加载的Module
      "PersonModule" => array("person" => "bob"),
      "FtpModule" => array("host" => "example.com", "user" => "anon")
    );
    
    private $modules = array();
    
    function init() {  #初始化ModuleRunner,加载配置中的Module
      $parent = new ReflectionClass("Module");
      foreach($this->configData as $moduleName => $params) {  #检查配置中的Module是否合法
        $moduleClass = new ReflectionClass($moduleName);
        if(! $moduleClass->isSubclassOf($parent)) {  #检查是否是Module的子类型
          throw new Exception("unknown type : {$moduleName}");
        }
        $module = $moduleClass->newInstance();
        foreach($moduleClass->getMethods() as $method) {  #检查配置中的函数的参数格式是否正确
          $this->handleMothod($module, $method, $params);
        }
        array_push($this->modules, $module);  #加载Module
      }
    }
    
    private function handleMothod(Module $module, ReflectionMethod $method, $params) {  #检查Module中的方法参数是

否和传入的$params名字相同,并且具有set方法
  

$name = $method->getName();
      $args = $method->getParameters();
    
      if(count($args) != 1 || substr($name, 0, 3) != "set") {  #如果没有配置中的类的方法的参数个数不为1,或者方法名前3个字母不为set,返回false
        return false;
      }
      
      $property = strtolower(substr($name, 3));
      if(!isset($params[$property])) {  #如果方法名后三个字母与配置中的参数名不同,返回false
        return false;
      }
      
      $argClass = $args[0]->getClass();  #获取参数的类型
      if(empty($argClass)) {
        $method->invoke($module, $params[$property]);  #参数无类型限制则直接调用set方法
      } else {
        $method->invoke($module, $argClass->newInstance($params[$property]));  #有类型限制则新建一个实例并调用set方法
      }
    }
    
    public function getModules() {
      return $this->modules;
    }
  }
  
  class Person {  #第三方类
    public $name;
    
    function __construct($name) {
      $this->name = $name;
    }
  }
  
  class FtpModule extends Module {  #用户自定义第三方Module
    private $host = "default host";
    private $user = "default user";
    
    function setHost($host) {
      $this->host = $host;
    }
    
    function setUser($user) {
      $this->user = $user;
    }
    
    function execute() {
      echo "{$this->user} user {$this->host}";
    }
  }
  
  class PersonModule extends Module {  #用户自定义第三方Module
    private $person;
  
    function setPerson(Person $person) {
      $this->person = $person;
    }
    
    function execute() {
      if(isset($person)) {
        echo "I am {$this->person->name}";
      } else {
        echo "I am no user";
      }
    }
  }
  
  $modRunner = new ModuleRunner();
  $modRunner->init();
  var_dump($modRunner);
?>

输出

object(ModuleRunner)#1 (2) { ["configData":"ModuleRunner":private]=> array(2) { ["PersonModule"]=> array(1) { ["person"]=> string(3) "bob" } ["FtpModule"]=> array(2) { ["host"]=> string(11) "example.com" ["user"]=> string(4) "anon" } } ["modules":"ModuleRunner":private]=> array(2) { [0]=> object(PersonModule)#4 (1) { ["person":"PersonModule":private]=> object(Person)#10 (1) { ["name"]=> string(3) "bob" } } [1]=> object(FtpModule)#3 (2) { ["host":"FtpModule":private]=> string(11) "example.com" ["user":"FtpModule":private]=> string(4) "anon" } } }

通过反射获得类源码

<?php
  function getSource(ReflectionClass $ref) {
    $path = $ref->getFileName();  #获取脚本文件文件名
    $file = file($path); #file()方法获取文件内容,并将内容保存在一个数组中,数组每个元素保存一行内容
    $start = $ref->getStartLine();  #获取类在脚本中的第一行行号
    $end = $ref->getEndLine();  #获取类在脚本中最后一行的行号
    $source = implode(array_slice($file, $start - 1, $end - $start + 1));  #拼装类源码
    
    var_dump($source);
  }

  class Person {
    public $age;
    private $name;
    
    function say() {
      echo "yes";
    }
  }
  
  $ref = new ReflectionClass("Person");
  getSource($ref);
?>
PHP 相关文章推荐
利用js调用后台php进行数据处理原码
Oct 09 PHP
php cli 方式 在crotab中运行解决
Feb 08 PHP
LotusPhp笔记之:Cookie组件的使用详解
May 06 PHP
深入PHP FTP类的详解
Jun 13 PHP
php实现下载限制速度示例分享
Feb 13 PHP
PHP资源管理框架Assetic简介
Jun 12 PHP
PHP判断表单复选框选中状态完整例子
Jun 24 PHP
php实现MySQL数据库备份与还原类实例
Dec 09 PHP
微信自定义菜单的处理开发示例
Apr 16 PHP
使用symfony命令创建项目的方法
Mar 17 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
Sep 29 PHP
Laravel Eloquent ORM 多条件查询的例子
Oct 10 PHP
基于php实现随机合并数组并排序(原排序)
Nov 26 #PHP
PHP随手笔记整理之PHP脚本和JAVA连接mysql数据库
Nov 25 #PHP
php实现遍历多维数组的方法
Nov 25 #PHP
WordPress迁移时一些常见问题的解决方法整理
Nov 24 #PHP
基础的WordPress插件制作教程
Nov 24 #PHP
优化WordPress的Google字体以加速国内服务器上的运行
Nov 24 #PHP
在WordPress中实现评论头像的自定义默认和延迟加载
Nov 24 #PHP
You might like
php开发中的页面跳转方法总结
2015/04/26 PHP
php实现网页端验证码功能
2017/07/11 PHP
PHP流Streams、包装器wrapper概念与用法实例详解
2017/11/17 PHP
php7 图形用户界面GUI 开发示例
2020/02/22 PHP
更换select下拉菜单背景样式的实现代码
2011/12/20 Javascript
jQuery 绑定事件到动态创建的元素上的方法实例
2013/08/18 Javascript
轻松使用jQuery双向select控件Bootstrap Dual Listbox
2015/12/13 Javascript
jquery html动态添加的元素绑定事件详解
2016/05/24 Javascript
Javascript中常用的检测方法小结
2016/10/08 Javascript
JavaScript数组push方法使用注意事项
2017/10/30 Javascript
vue 引入公共css文件的简单方法(推荐)
2018/01/20 Javascript
使用D3.js+Vue实现一个简单的柱形图
2018/08/05 Javascript
angular2实现统一的http请求头方法
2018/08/13 Javascript
ES6 Symbol在对象中的作用实例分析
2020/06/06 Javascript
js实现筛选功能
2020/11/24 Javascript
web.py获取上传文件名的正确方法
2014/08/26 Python
总结Python编程中函数的使用要点
2016/03/20 Python
python算法表示概念扫盲教程
2017/04/13 Python
基于python中staticmethod和classmethod的区别(详解)
2017/10/24 Python
Python将多个excel文件合并为一个文件
2018/01/03 Python
Python Pandas找到缺失值的位置方法
2018/04/12 Python
Python Subprocess模块原理及实例
2019/08/26 Python
详解python中index()、find()方法
2019/08/29 Python
Python迭代器Iterable判断方法解析
2020/03/16 Python
Python+OpenCV图像处理——实现轮廓发现
2020/10/23 Python
matplotlib更改窗口图标的方法示例
2021/02/03 Python
波兰补充商店:Muscle Power
2018/10/29 全球购物
加拿大国民体育购物网站:National Sports
2018/11/04 全球购物
结婚典礼证婚词
2014/01/11 职场文书
安全生产汇报材料
2014/02/17 职场文书
党员四风自我剖析材料
2014/10/07 职场文书
2015年乡镇党务公开工作总结
2015/05/19 职场文书
女性健康知识讲座主持词
2015/07/04 职场文书
Anaconda安装pytorch及配置PyCharm 2021环境
2021/06/04 Python
VUE使用draggable实现组件拖拽
2022/04/06 Vue.js
JS前端使用canvas实现扩展物体类和事件派发
2022/08/05 Javascript