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 相关文章推荐
我常用的几个类
Oct 09 PHP
php获取地址栏信息的代码
Oct 08 PHP
php自动给文章加关键词链接的函数代码
Nov 29 PHP
PHP中require和include路径问题详解
Dec 25 PHP
PHP获取Exif缩略图的方法
Jul 13 PHP
PHP序列化/对象注入漏洞分析
Apr 18 PHP
Thinkphp5结合layer弹窗定制操作结果页面
Jul 07 PHP
PHP+原生态ajax实现的省市联动功能详解
Aug 15 PHP
Laravel 实现密码重置功能
Feb 23 PHP
PHP实现Huffman编码/解码的示例代码
Apr 20 PHP
PHP设计模式之委托模式定义与用法简单示例
Aug 13 PHP
使用laravel指定日志文件记录任意日志
Oct 17 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顺序查找和二分查找示例
2014/03/27 PHP
Yii2使用dropdownlist实现地区三级联动功能的方法
2016/07/18 PHP
JQery jstree 大数据量问题解决方法
2010/03/09 Javascript
JavaScript 学习笔记二 字符串拼接
2010/03/28 Javascript
Ext对基本类型的扩展 ext,extjs,format
2010/12/25 Javascript
js修改table中Td的值(定义td的单击事件)
2013/01/10 Javascript
JS小游戏之仙剑翻牌源码详解
2014/09/25 Javascript
轻松创建nodejs服务器(8):非阻塞是如何实现的
2014/12/18 NodeJs
javascript实现类似于新浪微博搜索框弹出效果的方法
2015/07/27 Javascript
javascript实现网页背景烟花效果的方法
2015/08/06 Javascript
javascript实现C语言经典程序题
2015/11/29 Javascript
Bootstrap入门书籍之(一)排版
2016/02/17 Javascript
整理JavaScript对DOM中各种类型的元素的常用操作
2016/05/05 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
JS实现css hover操作的方法示例
2017/04/07 Javascript
javascript实现文件拖拽事件
2018/03/29 Javascript
浅谈vue-router路由切换 组件重用挖下的坑
2019/11/01 Javascript
微信小程序商品详情页底部弹出框
2019/11/22 Javascript
如何实现iframe父子传参通信
2020/02/05 Javascript
javascript实现贪吃蛇经典游戏
2020/04/10 Javascript
高效测试用例组织算法pairwise之Python实现方法
2017/07/19 Python
django 在原有表格添加或删除字段的实例
2018/05/27 Python
Python使用ctypes调用C/C++的方法
2019/01/29 Python
Python使用pandas和xlsxwriter读写xlsx文件的方法示例
2019/04/09 Python
python使用Matplotlib改变坐标轴的默认位置
2019/10/18 Python
python3 Scrapy爬虫框架ip代理配置的方法
2020/01/17 Python
Python中的X[:,0]、X[:,1]、X[:,:,0]、X[:,:,1]、X[:,m:n]和X[:,:,m:n]
2020/02/13 Python
keras 使用Lambda 快速新建层 添加多个参数操作
2020/06/10 Python
python os模块在系统管理中的应用
2020/06/22 Python
Python OpenCV去除字母后面的杂线操作
2020/07/05 Python
泰国办公用品购物网站:OfficeMate
2018/02/04 全球购物
最新销售员个人自荐信
2013/09/21 职场文书
五好家庭申报材料
2014/12/20 职场文书
关于拾金不昧的感谢信
2015/01/21 职场文书
见习期个人总结
2015/03/05 职场文书
原生JS中应该禁止出现的写法
2021/05/05 Javascript