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语法速查表
Dec 06 PHP
PHP实时显示输出
Oct 02 PHP
php中将图片gif,jpg或mysql longblob或blob字段值转换成16进制字符串
Aug 23 PHP
php文件操作实例代码
May 10 PHP
php用header函数实现301跳转代码实例
Nov 25 PHP
PHP结合JQueryJcrop实现图片裁切实例详解
Jul 24 PHP
PHP中使用substr()截取字符串出现中文乱码问题该怎么办
Oct 21 PHP
yii2分页之实现跳转到具体某页的实例代码
Jun 02 PHP
php版阿里云OSS图片上传类详解
Dec 01 PHP
超强多功能php绿色集成环境详解
Jan 25 PHP
详解php中serialize()和unserialize()函数
Jul 08 PHP
php正确输出json数据的实例讲解
Aug 21 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
用文本文件实现的动态实时发布新闻的程序
2006/10/09 PHP
IIS环境下快速安装、配置和调试PHP5.2.0
2006/12/17 PHP
PHP如何解决网站大流量与高并发的问题
2011/06/25 PHP
php检测文件编码的方法示例
2014/04/25 PHP
laravel安装zend opcache加速器教程
2015/03/02 PHP
PHP实现合并discuz用户
2015/08/05 PHP
JavaScript Event学习第三章 早期的事件处理程序
2010/02/07 Javascript
IE下使用cloneNode注意事项分享
2012/11/22 Javascript
JavaScript数值数组排序示例分享
2014/05/27 Javascript
JS数组(Array)处理函数整理
2014/12/07 Javascript
node.js中的console.trace方法使用说明
2014/12/09 Javascript
window.onload与$(document).ready()的区别分析
2015/05/30 Javascript
JavaScript是如何实现继承的(六种方式)
2016/03/31 Javascript
jquery实现图片列表鼠标移入微动
2016/12/01 Javascript
javascript工厂模式和构造函数模式创建对象方法解析
2016/12/30 Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
2017/02/18 Javascript
JS实现获取word文档内容并输出显示到html页面示例
2018/06/23 Javascript
详解Vue项目中出现Loading chunk {n} failed问题的解决方法
2018/09/14 Javascript
js正则匹配多个全部数据问题
2019/12/20 Javascript
electron踩坑之remote of undefined的解决
2020/10/06 Javascript
python绘制立方体的方法
2018/07/02 Python
Python利用matplotlib绘制约数个数统计图示例
2019/11/26 Python
使用IPython或Spyder将省略号表示的内容完整输出
2020/04/20 Python
python argparse模块通过后台传递参数实例
2020/04/20 Python
sublime3之内网安装python插件Anaconda的流程
2020/11/10 Python
Python+Appium实现自动化清理微信僵尸好友的方法
2021/02/04 Python
利用CSS3的特性改变文本选中时的颜色
2013/09/11 HTML / CSS
最便宜促销价格订机票:Airpaz(总部设在印尼,支持中文)
2018/11/13 全球购物
ETO男装官方网店:ETO Jeans
2019/02/28 全球购物
大学校园活动策划书
2014/02/04 职场文书
经典禁毒标语
2014/06/16 职场文书
上班迟到检讨书
2014/09/15 职场文书
党的群众路线对照检查材料
2014/09/22 职场文书
机票销售员态度不好检讨书
2014/09/27 职场文书
提升Nginx性能的一些建议
2021/03/31 Servers
MyBatis-Plus 批量插入数据的操作方法
2021/09/25 Java/Android