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 相关文章推荐
不用数据库的多用户文件自由上传投票系统(3)
Oct 09 PHP
如何在PHP程序中防止盗链
Apr 09 PHP
php实现两表合并成新表并且有序排列的方法
Dec 05 PHP
php实现TCP端口检测的方法
Apr 01 PHP
PHP入门教程之面向对象基本概念实例分析
Sep 11 PHP
thinkPHP批量删除的实现方法分析
Nov 09 PHP
PHP多维数组元素操作类的方法
Nov 14 PHP
php爬取天猫和淘宝商品数据
Feb 23 PHP
PHP中$GLOBALS与global的区别详解
Mar 21 PHP
PHP实现提高SESSION响应速度的几种方法详解
Aug 09 PHP
Laravel开启跨域请求的方法
Oct 13 PHP
php 利用socket发送GET,POST请求的实例代码
Jul 04 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代码
2010/07/17 PHP
PHP Class&amp;Object -- PHP 自排序二叉树的深入解析
2013/06/25 PHP
PHP限制页面只能在微信自带浏览器访问的代码
2014/01/15 PHP
php使用for语句输出三角形的方法
2015/06/09 PHP
How to Auto Include a Javascript File
2007/02/02 Javascript
关于 byval 与 byref 的区别分析总结
2007/10/08 Javascript
javascript 学习之旅 (1)
2009/02/05 Javascript
AngularJS入门教程之学习环境搭建
2014/12/06 Javascript
node.js中的fs.chownSync方法使用说明
2014/12/16 Javascript
jQuery中;function($,undefined) 前面的分号的用处
2014/12/17 Javascript
JS实现控制表格行文本对齐的方法
2015/03/30 Javascript
使用AmplifyJS组件配合JavaScript进行编程的指南
2015/07/28 Javascript
简单学习JavaScript中的for语句循环结构
2015/11/10 Javascript
推荐阅读的js快速判断IE浏览器(兼容IE10与IE11)
2015/12/13 Javascript
js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解
2016/04/01 Javascript
浅谈jquery中next与siblings的区别
2016/10/27 Javascript
javascript显示系统当前时间代码
2016/12/29 Javascript
Node.js安装配置图文教程
2017/05/10 Javascript
ES6 Iterator接口和for...of循环用法分析
2019/07/31 Javascript
ES6中的类(Class)示例详解
2020/12/09 Javascript
python实现的阳历转阴历(农历)算法
2014/04/25 Python
Python中方法链的使用方法
2016/02/23 Python
Python字典常见操作实例小结【定义、添加、删除、遍历】
2019/10/25 Python
基于python纯函数实现井字棋游戏
2020/05/27 Python
Python绘制K线图之可视化神器pyecharts的使用
2021/03/02 Python
微信浏览器左上角返回按钮拦截功能
2017/11/21 HTML / CSS
西班牙太阳镜品牌:Hawkers
2018/03/11 全球购物
主管职责范文
2013/11/09 职场文书
职员竞岗演讲稿
2014/05/14 职场文书
小学美术兴趣小组活动总结
2014/07/07 职场文书
贯彻落实“八项规定”思想汇报
2014/09/13 职场文书
综合素质评价个性发展自我评价
2015/03/06 职场文书
2015年城市管理工作总结
2015/05/23 职场文书
外出培训学习心得体会
2016/01/18 职场文书
python 如何将两个实数矩阵合并为一个复数矩阵
2021/05/19 Python
Nginx stream 配置代理(Nginx TCP/UDP 负载均衡)
2021/11/17 Servers