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 相关文章推荐
在线竞拍系统的PHP实现框架(二)
Oct 09 PHP
简单易用的计数器(数据库)
Oct 09 PHP
?算你??的 PHP 程式大小
Dec 06 PHP
PHP中的正则表达式函数介绍
Feb 27 PHP
使用PHP破解防盗链图片的一个简单方法
Jun 07 PHP
PHP 实现类似js中alert() 提示框
Mar 18 PHP
PHP常用的排序和查找算法
Aug 06 PHP
详解js异步文件加载器
Jan 24 PHP
thinkPHP实现将excel导入到数据库中的方法
Apr 22 PHP
PHP分页初探 一个最简单的PHP分页代码的简单实现
Jun 21 PHP
php实现的生成迷宫与迷宫寻址算法完整实例
Nov 06 PHP
php在windows环境下获得cpu内存实时使用率(推荐)
Feb 08 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
Yii中使用PHPExcel导出Excel的方法
2014/12/26 PHP
修改Laravel5.3中的路由文件与路径
2016/08/10 PHP
php版微信小店调用api示例代码
2016/11/12 PHP
jQuery点击tr实现checkbox选中的方法
2013/03/19 Javascript
Enter转换为Tab的小例子(兼容IE,Firefox)
2013/11/14 Javascript
Backbone.js的一些使用技巧
2015/07/01 Javascript
使用jspdf生成pdf报表
2015/07/03 Javascript
JavaScript中SetInterval与setTimeout的用法详解
2015/11/10 Javascript
javascript设置和获取cookie的方法实例详解
2016/01/05 Javascript
浅述节点的创建及常见功能的实现
2016/12/15 Javascript
[原创]SyntaxHighlighter自动识别并加载脚本语言
2017/02/07 Javascript
javascript实现的图片预览功能
2017/03/25 Javascript
layui实现动态和静态分页
2018/04/28 Javascript
详解Jest结合Vue-test-utils使用的初步实践
2019/06/27 Javascript
详解Vue中的自定义指令
2020/12/07 Vue.js
[04:37]DOTA2英雄梦之声Vol20发条
2014/06/20 DOTA
[44:58]2018DOTA2亚洲邀请赛 4.5 淘汰赛 LGD vs Liquid 第二场
2018/04/06 DOTA
Python使用PyCrypto实现AES加密功能示例
2017/05/22 Python
利用python求相邻数的方法示例
2017/08/18 Python
浅谈Python里面小数点精度的控制
2018/07/16 Python
python实现最小二乘法线性拟合
2019/07/19 Python
Django ImageFiled上传照片并显示的方法
2019/07/28 Python
给Python学习者的文件读写指南(含基础与进阶)
2020/01/29 Python
使用JS+CSS3技术:让你的名字动起来
2013/04/27 HTML / CSS
利用css3画个同心圆示例代码
2017/07/03 HTML / CSS
德国狗狗用品在线商店:Schecker
2017/03/17 全球购物
医生自荐信
2013/10/11 职场文书
4s店总经理岗位职责
2013/12/31 职场文书
宗教学大学生职业生涯规划范文
2014/02/08 职场文书
项目建议书格式
2014/03/12 职场文书
党员承诺书格式
2014/05/21 职场文书
护理专业自荐书
2014/06/04 职场文书
2019员工保密协议书(3篇)
2019/09/23 职场文书
Nginx开启Brotli压缩算法实现过程详解
2021/03/31 Servers
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
2022/03/23 MySQL
python运算符之与用户交互
2022/04/13 Python