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下防止单引号,双引号在接受页面转义的设置方法
Sep 25 PHP
PHP大小写问题:函数名和类名不区分,变量名区分
Jun 17 PHP
PHP利用APC模块实现文件上传进度条的方法
Jan 26 PHP
PHP 二维数组和三维数组的过滤
Mar 16 PHP
php字符串的替换,分割和连接方法
May 23 PHP
php使用include 和require引入文件的区别
Feb 16 PHP
如何用PHP做到页面注册审核
Mar 02 PHP
php求数组全排列,元素所有组合的方法总结
Mar 14 PHP
php5.5使用PHPMailer-5.2发送邮件的完整步骤
Oct 14 PHP
php利用ZipArchive类操作文件的实例
Jan 21 PHP
如何运行/调试你的PHP代码
Oct 23 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执行.SQL文件
2013/07/05 PHP
shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
2013/07/15 PHP
Codeigniter购物车类不能添加中文的解决方法
2014/11/29 PHP
smarty内置函数capture用法分析
2015/01/22 PHP
CodeIgniter 完美解决URL含有中文字符串
2016/05/13 PHP
PHP发送邮件确认验证注册功能示例【修改别人邮件类】
2019/11/09 PHP
js与jquery获取父元素,删除子元素的两种不同方法
2014/01/09 Javascript
基于zepto.js实现仿手机QQ空间的大图查看组件ImageView.js详解
2015/03/05 Javascript
JavaScript分页功能的实现方法
2015/04/25 Javascript
javascript委托(Delegate)blur和focus用法实例分析
2015/05/26 Javascript
js和jQuery设置Opacity半透明 兼容IE6
2016/05/24 Javascript
基于JavaScript实现类名的添加与移除
2017/04/23 Javascript
vue2.0+vue-router构建一个简单的列表页的示例代码
2019/02/13 Javascript
JavaScript数据结构与算法之二叉树添加/删除节点操作示例
2019/03/01 Javascript
使用Vue CLI创建typescript项目的方法
2019/08/09 Javascript
vue使用prop可以渲染但是打印台报错的解决方式
2019/11/13 Javascript
jquery选择器和属性对象的操作实例分析
2020/01/10 jQuery
javascript canvas实现简易时钟例子
2020/09/05 Javascript
python原始套接字编程示例分享
2014/02/21 Python
Python内置函数delattr的具体用法
2017/11/23 Python
使用pip发布Python程序的方法步骤
2018/10/11 Python
Python button选取本地图片并显示的实例
2019/06/13 Python
Django 自动生成api接口文档教程
2019/11/19 Python
python3 requests库实现多图片爬取教程
2019/12/18 Python
基于MSELoss()与CrossEntropyLoss()的区别详解
2020/01/02 Python
python opencv如何实现图片绘制
2020/01/19 Python
利用python画出AUC曲线的实例
2020/02/28 Python
安装pyinstaller遇到的各种问题(小结)
2020/11/20 Python
Css3新特性应用之视觉效果实例
2016/12/12 HTML / CSS
美国在线宠物商店:Chewy
2019/01/12 全球购物
个人授权委托书样本
2014/09/13 职场文书
结婚保证书
2015/01/16 职场文书
德能勤绩廉个人总结
2015/02/14 职场文书
2015年少先队活动总结
2015/03/25 职场文书
我对PyTorch dataloader里的shuffle=True的理解
2021/05/20 Python
pycharm安装深度学习pytorch的d2l包失败问题解决
2022/03/25 Python