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 变量定义方法
Jun 14 PHP
Wordpress php 分页代码
Oct 21 PHP
php 文件上传实例代码
Apr 19 PHP
探讨Smarty中如何获取数组的长度以及smarty调用php函数的详解
Jun 20 PHP
解析在zend Farmework下如何创立一个FORM表单
Jun 28 PHP
php缩小png图片不损失透明色的解决方法
Dec 25 PHP
PHP删除数组中空值的方法介绍
Apr 14 PHP
PHP发送短信代码分享
Aug 11 PHP
PHP Yii框架之表单验证规则大全
Nov 16 PHP
使用PHP uniqid函数生成唯一ID
Nov 18 PHP
thinkphp修改配置进入默认首页的方法
Feb 07 PHP
Laravel中如何轻松容易的输出完整的SQL语句
Jul 26 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购物网站支付paypal使用方法
2010/11/28 PHP
php格式化时间戳显示友好的时间实现思路及代码
2014/10/23 PHP
php站内搜索关键词变亮的实现方法
2014/12/30 PHP
php获取从百度、谷歌等搜索引擎进入网站关键词的方法
2015/07/08 PHP
php获取错误信息的方法
2015/07/17 PHP
PHP数组的定义、初始化和数组元素的显示实现代码
2016/11/05 PHP
PHP lcfirst()函数定义与用法
2019/03/08 PHP
Laravel框架Request、Response及Session操作示例
2019/05/06 PHP
jQuery EasyUI API 中文文档 - Dialog对话框
2011/11/15 Javascript
js写一个弹出层并锁屏效果实现代码
2012/12/07 Javascript
IE、FF、Chrome浏览器中的JS差异介绍
2013/08/13 Javascript
将List对象列表转换成JSON格式的类实现方法
2016/07/04 Javascript
jquery 多个radio的click事件实例
2016/12/03 Javascript
js实现文字选中分享功能
2017/01/25 Javascript
微信小程序 获取session_key和openid的实例
2017/08/17 Javascript
zTree节点文字过多的处理方法
2017/11/24 Javascript
jfinal与bootstrap的登出实战详解
2017/11/27 Javascript
vue实现文字横向无缝走马灯组件效果的实例代码
2019/04/09 Javascript
js简单的分页器插件代码实例
2019/09/11 Javascript
浅谈TypeScript 用 Webpack/ts-node 运行的配置记录
2019/10/11 Javascript
小程序input数据双向绑定实现方法
2019/10/17 Javascript
JavaScript实现音乐导航效果
2020/11/19 Javascript
整理Python最基本的操作字典的方法
2015/04/24 Python
Python 反转字符串(reverse)的方法小结
2018/02/20 Python
python实现两个文件合并功能
2018/04/01 Python
pandas ix &amp;iloc &amp;loc的区别
2019/01/10 Python
pytorch 实现模型不同层设置不同的学习率方式
2020/01/06 Python
Python实现bilibili时间长度查询的示例代码
2020/01/14 Python
Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow
2020/04/20 Python
Python如何实现后端自定义认证并实现多条件登陆
2020/06/22 Python
Python3.9.0 a1安装pygame出错解决全过程(小结)
2021/02/02 Python
浅析图片上传及canvas压缩的流程
2020/06/10 HTML / CSS
货物运输服务质量承诺书
2014/05/29 职场文书
红领巾广播站广播稿
2015/08/19 职场文书
高考百日冲刺决心书
2015/09/23 职场文书
win10识别不了U盘怎么办 win10系统读取U盘失败的解决办法
2022/08/05 数码科技